玩命加载中 . . .

线程


多线程与多进程

进程一般是对操作系统而言的;线程一般是对某程序而言的。
比如,打开word的同时打开outlook接收邮件,我们说这是两个进程;而打开outlook收取新邮件的同时查看已下载的邮件,我们就说这是两个进程。

线程的状态

Thread类

Java的线程是通过类Thread来实现的,生成一个Thread类的对象之后,就产生了一个线程;Thread类对象内部的run()方法会执行代码,被称为线程体。

新建—就绪—运行—阻塞—死亡

  • 新建状态:使用new关键字创建一个Thread线程对象,此时线程已有自己的内存空间,但是并不是活着的。
  • 就绪状态:调用start()方法
  • 运行状态:执行run()方法
  • 阻塞状态:调用join()、sleep()、wait()方法。
  • 死亡状态

创建线程

一般有两种方法创建线程:

  • 继承Thread方法
  • 实现Runnable接口
class ThreadInterfaceImpl implements Runnable {
    public void run() {
        // 线程实现体
    }
}
// 创建接口实现类的实例对象
Runnable target = new ThreadInterfaceImpl();
// 创建一个Thread类的对象,并将上步中创建的对象作为参数传递给Thread类的构造函数
Thread threadObject = new Thread(target);
/*
或者简写为:
Thread threadObject = new Thread(new ThreadInterfaceImpl())
*/
// 用start()方法启动线程
threadObject.start();

线程调度策略

Java采用抢占式策略,高优先级的线程抢占CPU。

void setPriority(int newPriority);  // 重置线程优先级
int getPriority();
static void yield();    // 给其他同等优先级的线程一个运行机会
void sleep();   // 使线程休眠一段时间
void join();    // 等待某个线程结束后再开始执行另一个线程

线程的基本控制

join()方法

关于join()方法,它的使用举一个栗子:
设置三个线程,线程1用于生成一群随机数,线程2用于计算随机数之和,线程3用于输出这个和,要求线程1、线程2、线程3依次运行。

package hitwh.hitwh.myThread;

//线程三,输出结果
public class PrintTask implements Runnable{
    Thread thread;
    public PrintTask(Thread thread) {
        this.thread = thread;
    }
    public void run() {
        try {
//            让接收的线程对象执行完,本线程才运行
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sum="+JoinDemo.sum);
    }
}

package hitwh.hitwh.myThread;

//线程1,用于产生随机数
public class Producer implements Runnable{
    int[] arr;
    public Producer(int []arr) {
        this.arr = arr;
    }
    //    线程体
    public void run() {
        System.out.println("初始化...");
        for(int i=0; i<arr.length;i++) {
            arr[i]=(int)(Math.random()*100);
            System.out.print(arr[i]+",");
            if((i+1)%10==0)
                System.out.println();
        }
    }
}
package hitwh.hitwh.myThread;

//线程2,计算线程一产生的随机数的和
public class Worker implements Runnable{
    int[] arr;
    Thread thread;
//    构造方法,接收一个数组和一个线程对象
    public Worker(int[] arr, Thread thread) {
        this.arr = arr;
        this.thread = thread;
    }
//    线程体
    public void run() {
        try {
//            让接收的线程执行完,本线程才会执行
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("开始计算...");
//        计算数组中所有元素之和
        int sum = 0;
        for(int i=0; i<arr.length; i++) {
            sum+=arr[i];
        }
        JoinDemo.sum=sum;
    }
}

package hitwh.hitwh.myThread;

public class JoinDemo {
    static int sum = 0;

    public static void main(String[] args) throws InterruptedException {
        int[] arr = new int[10];
//        先启动线程一,生成一群随机数
        Thread producer = new Thread(new Producer(arr));
        producer.start();
//        后启动线程二,计算线程一生成的随机数之和
        Thread worker = new Thread(new Worker(arr, producer));
        worker.start();
//        最后启动线程三,输出结果
        Thread printTask = new Thread(new PrintTask(worker));
        printTask.start();
//        等待printTask线程对象执行完,程序才继续运行
        printTask.join();

        int sum1 = 0;
        for(int i=0; i<arr.length; i++) {
            sum1+=arr[i];
        }
        if(sum == sum1) {
            System.out.println("验证通过!");
        } else {
            System.out.println("验证失败!"+" sum="+sum+", sum1="+sum1);
        }
    }
}

结束线程与中断线程

run()线程体运行结束时,该线程自然死亡;
stop()方法可以强制停止线程执行(不推荐使用)

使用interrupt()方法可以使线程中断执行。
一般地,在程序中调用interrupt()方法后,通常需要在run()方法中使用isInterrupt()进行判断,根据判断结果执行相应操作。

线程间的通信

设置三个线程类,通信的双方线程作为辅类线程,都将数据流连接到主类中的管道流中。

package hitwh.hitwh.commuThread;

import java.io.DataInput;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.PipedInputStream;

public class MyReader1 extends Thread{
//    创建管道输入流
    private PipedInputStream pis;
//    创建数据输入流
    private DataInputStream dis;
//    接收数据
    private String messages[];

    public MyReader1(PipedInputStream pis) {
        this.pis = pis;
    }
    public void run() {
//        将数据输入流与管道输入流联系起来
        dis = new DataInputStream(pis);
        try {
            int size = dis.read();
            messages = new String[size];
            // 读数据
            for(int i=0; i<messages.length; i++) {
                messages[i] = dis.readUTF();
                System.out.println("Read:"+messages[i]);
                try {
                    sleep(400);
                } catch (InterruptedException e) {}
            }
        } catch (IOException e) {}
    }
}

package hitwh.hitwh.commuThread;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PipedOutputStream;

//写线程
public class MyWriter1 extends Thread{
//    创建管道输出流
    private PipedOutputStream pos;
    // 创建数据输出流
    private DataOutputStream dos;
    private int size = 7;
//    要写的数据源
    private String messages[] = {"Mon", "Tues", "Wednes", "Thur", "Fri", "Satur", "Sun"};
    public MyWriter1(PipedOutputStream pos) {
        this.pos = pos;
    }
    public void run() {
//        用 管道输出流 和 写线程的数据输出流 联系起来
        dos = new DataOutputStream(pos);
        try {
            dos.write(size);
            for(int i=0; i<messages.length; i++) {
                dos.writeUTF(messages[i]);
                System.out.println("Writte:"+messages[i]);
                try {
                    sleep(300);
                } catch (InterruptedException e) {}
            }
            dos.close();
        } catch (IOException e) {}
    }
}

package hitwh.hitwh.commuThread;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class PipeThread {
    public static void main(String[] args) {
        PipeThread thisPipe = new PipeThread();
        thisPipe.process();
    }
    public void process() {
        PipedInputStream inputStream;
        PipedOutputStream outputStream;
        try {
//            建立管道输入流与管道输出流之间的连接
            outputStream = new PipedOutputStream();
            inputStream = new PipedInputStream(outputStream);
//            读线程与写线程一起运行
            new MyWriter1(outputStream).start();
            new MyReader1(inputStream).start();
        } catch (IOException e) {}
    }
}

线程的同步

线程间的资源互斥

在多个线程共享同一资源的情况下,如果不加以任何控制,就有可能产生访问冲突和数据不一致。
为了解决这样的问题,就需要给多个线程共享的资源加锁。当一个线程访问共享资源时,就会被共享资源加锁,其他线程就不能访问被加了锁的资源,直到共享资源的锁被释放。这就是线程同步。
在Java中,用关键字synchronize来保证线程同步。当它作用于方法时,称方法同步;作用于语句块时,称为语句块同步。

线程交互

等待集合

每一个类的对象实例都有一个等待集合,当在实例上调用方法wait后,线程都会进入到该实例的等待集合中,除非发生下列情况:

  • 其他线程调用了方法notify()或者notifyAll();
  • 其他线程调用了方法interrupt()中断该线程
  • 方法wait()的等待时间结束
  1. wait()
    wait()方法是类Object中的方法。当线程调用了方法wait()后,当前线程就会进入休眠状态,并且释放对象同步锁的控制权。
  2. notify()
    线程不能一直停留在等待集合中,notify可以从将某个对象的等待集合中选择一个等待的线程进行唤醒。
  3. notifyAll()
    唤醒所有等待的线程。

文章作者: 鹿卿
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 鹿卿 !
评论
  目录