zoukankan      html  css  js  c++  java
  • 线程

    线程终止

    ① 因为 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()+"	"+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不会释放同步监视器
  • 相关阅读:
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    mysql备份及恢复
    mysql备份及恢复
    mysql备份及恢复
  • 原文地址:https://www.cnblogs.com/huyuqing/p/14343396.html
Copyright © 2011-2022 走看看