《图解Java多线程设计模式》之一:基础

一,什么是线程?
1.java中把正在执行程序的主体称为线程。
2.单线程:
当我们在阅读程序时,会根据处理流程来阅读,比如:首先执行前面的语句,然后再执行后面的语句,我们试着用笔将执行顺序描画出来,会发现描画出来的是一条弯弯曲曲的长线。这条长线始终是一条,无论调方法还是执行复杂的逻辑,对于这种处理流程始终如一条线的程序,称之为单线程程序。在单线程程序中,在某一个时间点执行的处理只有一个。
3.多线程
多个线程同时执行
3.应用场景
客户端应用程序
耗时的I/O处理
多个客户端:同时处理多个客户端

二,Thread类
1.启动线程必须使用线程类

public class MyThread extends Thread{

    public void run(){
        for(int i=0;i<100;i++){
            System.out.println("hello");        
        }
    }
}

新启动的线程的操作都编写在run方法中,新线程启动后,会调用run方法。当run方法执行结束后,线程也会跟着终止

2.启动一个线程

public class Main{
    public static void main(String[] args){
        MyThread t = new MyThread();//创建线程
        t.start();//启动线程

        for(int i = 0;i<100;i++){
            System.out.println("world");
        }
    }
}

理解:上面代码中有两个线程,首先执行main方法,这个一个主线程。当执行到 t.start()时,会开启一个新的线程,该线程打印hello。
  同时主线程继续向下执行,并打印world。这个程序运行着两个线程,所以这是一个多线程程序。

注意:启动线程调用的是start方法,不是run方法。当调用start方法后,程序会在后台启动新的线程。然后由这个新线程调用run方法。
      start方法做了两件事,启动新线程,调用run方法

public class PrintThread extends Thread {
    private String message;
    public PrintThread(String message){
        this.message = message;
    }
    public void run(){
        for (int i = 0; i <1000 ; i++) {
            System.out.println(message);
        }
    }
}

--------------------------------------------------------------------
public class Test {
    public static void main(String[] args) {
        new PrintThread("aaa").start();
        new PrintThread("bbb").start();
    }
}

这里新开启了两个线程,aaa和bbb交替打印

--------------------------------------------------------------------
public class Test {
    public static void main(String[] args) {
        new PrintThread("aaa").run();
        new PrintThread("bbb").run();
    }
}

这里只是创建了两个对象,并调用对象的run方法,先打印aaa在打印bbb

注意上面的区别

三,创建线程的方式
1.继承Thread类

public class MyThread extends Thread{

    public void run(){
        for(int i=0;i<100;i++){
            System.out.println("hello");        
        }
    }
}

注意:Thread类本身实现了Runnable接口,并且持有run方法,但Thread类的run方法主体是空的,不执行任何操作。
  Thread类的run方法通常由子类run方法重写。

2.实现Runnable接口

public class MyRunnable implements Runnable{
    public void run(){
        for(int i = 0;i<100;i++){
            System.out.println("world");
        }
    }
}
----------------------------------------------------------

Runnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();

3.java.util.concurrent.ThreadFactory中的线程创建

public class Main{
    public static void main(String[] args){
        Runnable r = new MyRunnable();
        ThreadFactory factory = Executors.defaultThreadFactory();
        factory.newThread(r).start();

        for(int i = 0;i<100;i++){
            System.out.println("good");
        }
    } 
}

四,线程的暂停

Thread.sleep();
sleep方法必须try...catch。因为sleep方法会抛出InterruptedException异常。InterruptedException异常能够取消线程的处理。
五,线程的互斥处理
防止多个线程同时操作同一个资源,引起结果和预期不相同。
1.synchronized方法
一个实例中的synchronized方法每次只能由一个线程运行。每个实例都拥有一个独立的锁。
synchronized方法的使用的是对象锁,synchronized静态方法使用的是类的类对象的锁(MyThread.class)。他们两个锁不一样
六,线程的协作
1.等待队列
所有实例拥有一个等待队列,他是在实例的wait方法执行后停止操作的线程的队列。就好比是为每一个实例准备的线程休息室
2.wait方法:把线程放入等待队列
执行了 obj.wait();当前线程就会暂停运行,并进入实例obj的等待队列中
注意:若要执行wait方法,线程必须持有锁。但如果线程进入等待队列,就会释放实例的锁
3.notify方法:从等待队列中取出线程
执行了obj.notify(); obj的等待队列的一个线程就会被选中和唤醒,然后就会退出等待队列。若要执行notify方法,线程也必须要持有调用的实例的锁
注意:notify唤醒的线程并不会在执行notify的一瞬间重新运行,因为在执行nofity的那一瞬间,执行notify的线程还持有锁,
其他线程还无法获取这个实例的锁
4.notifyAll方法:从等待队列中取出所有的线程
obj.notifyAll();
5.如果线程未持有锁的情况下调用wait,notify,notifyAll方法,会怎样?
抛异常:IllegalMonitorStateException 

七,线程的状态转移

待续

原文地址:https://www.cnblogs.com/inspred/p/9369606.html