线程

线程终止

① 因为 run 方法正常退出而自然死亡
② 因为一个没有捕获的异常终止了 run 方法而意外死亡

线程状态

线程优先级

每一个线程有一个优先级。默认情况下, 一个线程继承它的父线程的优先级。 可以用 setPriority 方法提高或降低任何一个线程的优先级。可以将优先级设置为在 MIN_PRIORITY (在 Thread 类中定义为 1 ) 与 MAX_PRIORITY (定义为 10 ) 之间的任何值。NORM_PRIORITY 被定义为 5。

创建一个线程方式

方式一:继承Thread类

/**
步骤:
  1. 声明一个类,让其继承Thread类,该类成为子类
  2. 重写Thread类的run方法 
  3. 调用该类 的 实例并 start
public static void main(String[] args) {
        MyThread myThread = new MyThread();
        //start() 作用: 
        /**
          Causes this thread to begin execution;  执行该线程
          the Java Virtual Machine calls the run method of this thread. 调用 当前线程 run
        */
        myThread.start();
}

class MyThread extends Thread{
    @Override
    public void run() {
        //do something
        System.out.println("具体处理");
    }
}

// 线程常用方法
System.out.println(MyThread.currentThread()); Thread[main,5,main]
System.out.println(myThread.getName());  Thread-0

方式一的卖票问题


public class ThreadTest {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        ticket.start();

        Ticket ticket1 = new Ticket();
        ticket1.start();

        Ticket ticket2 = new Ticket();
        ticket2.start();

    }
}
class Ticket extends Thread{
    static int ticket = 10;
    @Override
    public void run() {

        while (true){
            if (ticket > 0){
                System.out.println(Thread.currentThread().getName()+"票数:"+ticket);
                ticket--;
            }else {
                break;
            }
        }
    }
}
/**
结果:
Thread-0票数:5
Thread-0票数:4
Thread-0票数:3
Thread-0票数:2
Thread-0票数:1
Thread-1票数:5
Thread-2票数:5
*/

方式二:实现Runnable接口


/**
   1. 编写一个类 实现Runnable接口
   2. 实现接口中run方法
   3. 创建该类对象,把此对象当作参数传递给Thread构造器中,创建Thread对象
   4. 通过Thread对象调用start方法
 public static void main(String[] args) {
        MyThread2 myThread2 = new MyThread2();
        Thread thread = new Thread(myThread2);
        thread.start();
    }
}
class MyThread2 implements Runnable{
    @Override
    public void run() {
        //doSomething
        System.out.println("doSomething");
    }
}
*/

方式二的卖票问题


public class ThreadTest1 {
    public static void main(String[] args) {
        Target2 target2 = new Target2();
        Thread thread = new Thread(target2);
        thread.start();

        Thread thread1 = new Thread(target2);
        thread1.start();

        Thread thread2 = new Thread(target2);
        thread2.start();
    }
}
class Target2 implements Runnable{
    int target2 = 5;
    @Override
    public void run() {
        //doSomething
        while (true){
            if (target2 > 0){
                System.out.println(Thread.currentThread().getName()+"票数:"+target2);
                target2--;
            }else {
                break;
            }
        }
    }
}
/**
 结果:
Thread-0票数:5
Thread-0票数:4
Thread-0票数:3
Thread-0票数:2
Thread-2票数:5
Thread-2票数:1
Thread-1票数:5
*/

创建线程的第三种方式Callable-尚未补充

//待补充

创建线程的第四种方式 线程池:Executors-尚未补充

//待补充

线程安全-synchronized方式

/**
对两种创建线程的方式 进行加锁处理,该处理有两种解决方案,
同步代码块和同步方法。
对共享的代码进行加锁处理,多个线程需要共用一把锁
*/
public class ThreadTest1 {
    public static void main(String[] args) {
        Target2 target2 = new Target2();
        Thread thread = new Thread(target2);
        thread.start();

        Thread thread1 = new Thread(target2);
        thread1.start();

        Thread thread2 = new Thread(target2);
        thread2.start();
    }
}
class Target2 implements Runnable{
    int target2 = 5;
    @Override
    public void run() {
        //doSomething
        while (true){
            synchronized (this){ //this表示当前对象,在此处且唯一
                if (target2 > 0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"票数:"+target2);
                    target2--;
                }else {
                    break;
                }
            }
        }
    }
}
/** 结果:
Thread-1票数:5
Thread-1票数:4
Thread-1票数:3
Thread-1票数:2
Thread-1票数:1
*/


public class ThreadTest {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        ticket.start();

        Ticket ticket1 = new Ticket();
        ticket1.start();

        Ticket ticket2 = new Ticket();
        ticket2.start();

    }
}
class Ticket extends Thread{
    static int ticket = 5;
    private static Object o = new Object(); //对象o唯一
    @Override
    public void run() {

        while (true){
            synchronized (o){ //o可替换为 Ticket.class
                if (ticket > 0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"票数:"+ticket);
                    ticket--;
                }else {
                    break;
                }
            }
        }
    }
}
/** 结果:
Thread-0票数:5
Thread-0票数:4
Thread-0票数:3
Thread-0票数:2
Thread-0票数:1
*/

// 也可用同步方法改写,把共享代码写入一个方法中,加synchronized关键字即可。如:
public synchronized void methodName(){};

线程安全-Reentrant 方式

// 用 ReentrantLock 保护代码块的基本结构如下:
myLock.lock(); // a ReentrantLock object
try{
    critical section
}
finally{
    myLock.unlockO;// make sure the lock is unlocked even if an exception is thrown
}

example

public class ReentrantTest {
    public static void main(String[] args) {
        test1();
    }

    public static void test1(){
        Ticket2 ticket2 = new Ticket2();

        Thread thread = new Thread(ticket2);
        thread.start();

        Thread thread1 = new Thread(ticket2);
        thread1.start();

        Thread thread2 = new Thread(ticket2);
        thread2.start();
    }
}
class Ticket2 implements Runnable{

    private int ticket = 100;
    private ReentrantLock lock = new ReentrantLock(); //第三种方式

    @Override
    public void run() {
        while (true){
            try {
                lock.lock();  //锁住
                if (ticket > 0){
                    System.out.println(Thread.currentThread().getName()+"票数:"+ticket);
                    ticket--;
                }else {
                    break;
                }
            }finally {
                lock.unlock();  //开锁
            }
        }
    }
}

synchronized 和 ReentrantLock的区别

ReentrantLock 需要手动上锁 和 手动解锁

条件对象 Condition

待补充

线程通信

/**
  wait(): 表示 当前线程进入 阻塞 状态,并释放同步监视器
  notify(): 唤醒 被阻塞(wait)的线程,若有多个线程被阻塞,则唤醒优先级高的线程
  notifyAll(): 唤醒所有被阻塞的线程
这三个方法必须 放在同步代码块和同步方法中;
这三个方法必须是同步代码块或同步方法中和监视器同一个对象;
这三个方法都位于Object类中
*/
public class ReentrantTest {
    public static void main(String[] args) {
        test2();
    }

    public static void test2(){
        Clock c1 = new Clock();
        c1.start();

        Clock c2 = new Clock();
        c2.start();
    }
}

class Clock extends Thread{
    private static int count = 10;

    @Override
    public void run() {
        while (true){
            synchronized (Clock.class){
                Clock.class.notify(); //表示 唤醒被阻塞(wait())的线程;notifyAll: 唤醒所有阻塞线程
                if (count >= 0){
                    System.out.println(Thread.currentThread().getName()+"\t"+count);
                    count--;
                    try {
                        Clock.class.wait(); //wait和notify需要和监视器一致
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else {
                    break;
                }
            }
        }
    }
}

sleep 和 wait 异同

  - 都可以表示 线程 阻塞
  - sleep 位于 Thread类中,wait位于Object类中
  - sleep 任何 场景调用,wait 只能在同步代码块或同步方法中调用
  - 若两个方法都用在了 同步代码块或同步方法中,则wait 可以释放同步监视器,sleep不会释放同步监视器
posted @ 2021-01-29 10:09  先生胡  阅读(65)  评论(0编辑  收藏  举报