写作时间:2019-10-11
实现目标:总结Java线程概念,线程并发情况与解决方案
涉及知识:Java多线程

【思维导图】





【线程的创建】

线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位

线程创建基本方式为: 继承Thread类 实现Runnable接口 通过 Callable 和 Future 创建线程

//继承Thead类

package com.thread;

public class ThreadTest extends Thread{
    int i = 0;
    //重写run方法,run方法的方法体就是现场执行体
    public void run(){
        for(;i<100;i++){
        System.out.println(Thread.currentThread().getName()+"  "+i);

        }
    }
    public static void main(String[] args){
        for(int i = 0;i< 100;i++){
            System.out.println(Thread.currentThread().getName()+"  : "+i);
            if(i==20){
                new FirstThreadTest().start();
                new FirstThreadTest().start();
            }
        }
    }
}
//`实现Runnable接口`

package com.thread;

public class RunnableTest implements Runnable{
    public void run(){
        for(;i<100;i++){
        System.out.println(Thread.currentThread().getName()+"  "+i);

        }
    }
    public static void main(String[] args){
        for(int i = 0;i< 100;i++){
            System.out.println(Thread.currentThread().getName()+"  : "+i);
            if(i==20){
                RunnableTest rtt = new RunnableTest();
                new Thread(rtt,"新线程1").start();
                new Thread(rtt,"新线程2").start();

            }
        }
    }
}
//通过 Callable 和 Future 创建线程

package com.thread;

public class CallableThreadTest implements Callable<Integer> {
    public static void main(String[] args) {  
        CallableThreadTest ctt = new CallableThreadTest();  
        FutureTask<Integer> ft = new FutureTask<>(ctt);  
        for(int i = 0;i < 100;i++) {  
            System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);  
            if(i==20) {  
                new Thread(ft,"有返回值的线程").start();  
            }  
        }  
        try {  
            System.out.println("子线程的返回值:"+ft.get());  
        } catch (InterruptedException e){  
            e.printStackTrace();  
        } catch (ExecutionException e)  {  
            e.printStackTrace();  
        }  

    }

    public Integer call() throws Exception  {  
        int i = 0;  
        for(;i<100;i++) {  
            System.out.println(Thread.currentThread().getName()+" "+i);  
        }  
        return i;  
    }  
}

【线程的状态】

线程的状态分析:

新建状态(New):新创建了一个线程对象。

就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。

运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。

阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
    等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。(wait会释放持有的锁)
    同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
    其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。(注意,sleep是不会释放持有的锁)

死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

【线程的常用方法】

        currentThread() 返回当前正在执行的线程对象的引用
        getName() 返回此线程的名称
        getPriority() 返回此线程的优先级
        setName(String name) 改变该线程的名称等于参数 name  
        setPriority(int newPriority) 更改此线程的优先级 
        sleep(long millis) 当前正在执行的线程休眠
        interrupt() 中断这个线程(sleep,join,wait)
        join() 等待该线程死亡
        setDaemon(boolean on) 标志着该线程是 daemon线程或用户线程
            GC对应的线程是守护线程
        yield() 线程礼让 暂停当前正在执行的线程对象,并执行其他线程

【线程不安全问题】

首先我们要了解线程不安全问题是如何产生的

多线程的环境下 多个线程使用共同的资源 同时修改这个共同的资源产生了线程不安全问题

要解决线程不安全问题 有这几个解决方式:

同步方法,把 synchronized 作用在方法上

同步代码, synchronized 作用在公共变量上111

特殊域变量,使用 volatile 关键字修饰的变量,保证一个最新值

重入锁,在 JDK 中提供了一把锁的机制, java.util.concurrent.ReentrantLock 类,lock()加锁,unlock()解锁

线程变量(局部变量),把全局属性交个 ThreadLocal 管理,可以把全局变量转换成局部变量处理,使用 set 赋值、 get 取值单例对象多例属性

阻塞队列,队列一定能保证先进先出

原子变量实现线程同步

【线程死锁】

Java 多线程中的死锁 死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务

代码如下

public class LockTest {
   public static String obj1 = "obj1";
   public static String obj2 = "obj2";
   public static void main(String[] args) {
      LockA la = new LockA();
      new Thread(la).start();
      LockB lb = new LockB();
      new Thread(lb).start();
   }
}
class LockA implements Runnable{
   public void run() {
      try {
         System.out.println(new Date().toString() + " LockA 开始执行");
         while(true){
            synchronized (LockTest.obj1) {
               System.out.println(new Date().toString() + " LockA 锁住 obj1");
               Thread.sleep(3000); // 此处等待是给B能锁住机会
               synchronized (LockTest.obj2) {
                  System.out.println(new Date().toString() + " LockA 锁住 obj2");
                  Thread.sleep(60 * 1000); // 为测试,占用了就不放
               }
            }
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}
class LockB implements Runnable{
   public void run() {
      try {
         System.out.println(new Date().toString() + " LockB 开始执行");
         while(true){
            synchronized (LockTest.obj2) {
               System.out.println(new Date().toString() + " LockB 锁住 obj2");
               Thread.sleep(3000); // 此处等待是给A能锁住机会
               synchronized (LockTest.obj1) {
                  System.out.println(new Date().toString() + " LockB 锁住 obj1");
                  Thread.sleep(60 * 1000); // 为测试,占用了就不放
               }
            }
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}

解决方式为: 等待(wait)唤醒(notify)机制


【未完待续……】

您的喜欢是作者写作最大的动力!❤️
  • PayPal
  • AliPay
  • WeChatPay
  • QQPay
YAN