Java并发编程JUC入门(一) 线程与进程的概念

一 JUC概述

1 进程和线程

线程:指在系统中正在运行的一个应用程序;程序一旦运行就是进程;资源分配的最小单位

进程:系统分配处理器时间的基本单元,或者说是进程内独立执行的一个单元执行流。程序执行的最小单位

2.线程的五大状态

  1. NEW(新建)
  2. RUNNABLE(准备就绪)
  3. BLOCKED(阻塞)
  4. WAITING(不见不散)
  5. TIMED_WAITING(超时不候)
  6. TERMINATED(终结)

3.wait() 和 sleep()区别

  1. wait()是Object的方法,任何对象都能调用;而sleep()是Thread的静态方法。
  2. sleep抱锁睡觉,wait放开锁睡觉,在哪睡在哪醒
  3. 它们都可以被interrupted方法中断

4.并发和并行的区别

  1. 并行:多CPU,执行多任务,**应用:**泡方便面,电壶烧水,一边撕开调料倒入桶种
  2. 并发:单CPU,执行多任务。多个线程对应一个点,**应用:**春运车票,电商秒杀

5.管程

在这里插入图片描述

6.用户线程和守护线程

  1. 用户线程:自定义线程(new xxx),主线程结束,用户线程还在运行,jvm存活

    package new_course;
    
    /**
     * @author Created by Lin Weihong
     * @date on 2022/5/31 19:33
     */
    public class Test1 {
          
          
        public static void main(String[] args) {
          
          
            new Thread(() -> {
          
          
                System.out.println(Thread.currentThread().getName() + "::" + Thread.currentThread().isDaemon());
                while (true) {
          
          
                }
            }, "aa").start();
    
            System.out.println(Thread.currentThread().getName()+"Over");
        }
    }
    
    //运行结果,程序不会退出
    mainOver
    aa::false //表示不是守护线程
    
  2. 守护线程:垃圾回收(运行在后台),没有用户线程,都是守护线程,jvm结束

    /**
     * @author Created by Lin Weihong
     * @date on 2022/5/31 19:33
     */
    public class Test1 {
          
          
        public static void main(String[] args) {
          
          
            Thread aa = new Thread(() -> {
          
          
                System.out.println(Thread.currentThread().getName() + "::" + Thread.currentThread().isDaemon());
                while (true) {
          
          
                }
            }, "aa");
            aa.setDaemon(true);//设置为守护线程
            aa.start();
    
            System.out.println(Thread.currentThread().getName()+"Over");
        }
    }
    
    //运行结果,程序自动退出
    mainOver
    aa::true
    

二 Lock接口

1 复习Synchronized

多线程编程步骤

  1. 第一步 创建资源类,在资源类种创建属性和操作方法
  2. 第二步创建多个线程,调用资源类的操作方法
package new_course.chp2.sycn;

/**
 * @author Created by Lin Weihong
 * @date on 2022/5/31 20:00
 */
//1.第一步 创建资源类,在资源类种创建属性和操作方法
class Ticket {
    
    
    //票数
    private int number = 30;

    //操作方法
    public synchronized void sale() {
    
    
        //判断是否有票
        if (number > 0) {
    
    
            System.out.println(Thread.currentThread().getName() + "卖出了第" + number-- + "张票,还剩下" + number);

        }
    }

}

public class SaleTicket {
    
    
    //2.第二步创建多个线程,调用资源类的操作方法
    public static void main(String[] args) {
    
    
        //创建Ticket
        Ticket ticket = new Ticket();
        new Thread(() -> {
    
    
            for (int i = 0; i < 40; i++) {
    
    

                ticket.sale();
            }
        }, "aa").start();
        new Thread(() -> {
    
    
            for (int i = 0; i < 40; i++) {
    
    

                ticket.sale();
            }
        }, "bb").start();
        new Thread(() -> {
    
    
            for (int i = 0; i < 40; i++) {
    
    

                ticket.sale();
            }
        }, "cc").start();
    }
}

2 Lock接口

Lock和Synchronized区别

  1. Lock不是Java语言内置的,synchronized是Java语言关键字,因此是内置特性;Lock是一个类,通过这个类可以实现同步访问
  2. synchronized不需要手动释放锁,当synchronized方法或者synchronized代码块执行完之后,或者出现异常,系统会自动让线程释放对锁的占用;而Lock则必须要用户去手动释放锁(在finally语句中执行),如果没有主动释放锁,可能会出现死锁现象。
  3. Lock可以提高多个线程进行读操作的效率。
  4. 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
  5. Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断。

在资源竞争大的时候,Lock的效率大于synchronized

Lock之卖票案例

package new_course.chp2.lock;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Created by Lin Weihong
 * @date on 2022/5/31 23:44
 */
//第一步:创建资源类,定义属性和操作方法
class LTicket {
    
    
    //票数量
    private int number = 30;

    //创建可重入锁
    private final ReentrantLock lock = new ReentrantLock();

    //方法
    public void sale() {
    
    
        //上锁
        lock.lock();
        try {
    
    
            if (number > 0) {
    
    
                System.out.println(Thread.currentThread().getName() + "卖出了第" + number-- + "张票,还剩下" + number);
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            //解锁
             lock.unlock();
        }
    }
}


public class LSaleTicket {
    
    
    //第二步,创建多个线程,调用资源类的操作方法
    public static void main(String[] args) {
    
    
        LTicket ticket = new LTicket();
        new Thread(() -> {
    
    
            for (int i = 0; i < 40; i++) {
    
    
                ticket.sale();
            }
        },"aa").start();

        new Thread(() -> {
    
    
            for (int i = 0; i < 40; i++) {
    
    
                ticket.sale();
            }
        },"bb").start();

        new Thread(() -> {
    
    
            for (int i = 0; i < 40; i++) {
    
    
                ticket.sale();
            }
        },"cc").start();
    }
}

三 线程之间的通信

在这里插入图片描述

synchronized实现

package new_course.chp2.increment_decrement;

import sun.security.krb5.internal.Ticket;

/**
 * @author Created by Lin Weihong
 * @date on 2022/6/1 0:21
 * 题目需求:两个线程交替+1 -1 20轮,使得结果最后仍为0
 */
public class ThreadDemo01 {
    
    
    public static void main(String[] args) {
    
    
        //第三步
        Share share = new Share();
        new Thread(() -> {
    
    
            for (int i = 0; i < 10; i++) {
    
    
                try {
    
    
                    //+1方法
                    share.incr();
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        }, "aa").start();

        new Thread(() -> {
    
    
            try {
    
    
                for (int i = 0; i < 10; i++) {
    
    
                    // -1方法
                    share.decr();
                }
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        },"bb").start();
    }
}

//第一步
class Share {
    
    

    private int number = 0;

    public synchronized void incr() throws InterruptedException {
    
    
        //第二步 判断 干活 通知
        //if (number != 0) { //判断,不是0,就等待,存在虚假唤醒。
        while(number != 0) {
    
    // 解决虚假唤醒
            wait();
        }
        number++;//干活
        System.out.println(Thread.currentThread().getName() + "::" + number);
        //通知其他线程
        notifyAll();
    }

    public synchronized void decr() throws InterruptedException {
    
    
        //if (number != 1) {
    
    
        while(number != 1) {
    
    // 解决虚假唤醒
            wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName() + "::" + number);
        notifyAll();
    }
}

上面的代码会存在虚假唤醒的情况,问题出在if语句,可能会有多个线程进入if语句中进行等待。

Lock实现

package new_course.chp2.increment_decrement;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Created by Lin Weihong
 * @date on 2022/6/1 18:25
 */
//创建资源类
class TShare {
    
    
    //定义属性
    private int number = 0;

    //创建Lock
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();


    //操作方法
    public void incr() {
    
    
        lock.lock();
        try {
    
    
            //判断
            while (number != 0) {
    
    
                condition.await();
            }
            //干活
            number++;
            System.out.println(Thread.currentThread().getName() + "::" + number);
            //通知
            condition.signalAll();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            lock.unlock();
        }
    }

    public void decr() {
    
    
        lock.lock();
        try {
    
    
            //判断
            while (number != 1) {
    
    
                condition.await();
            }
            //干活
            number--;
            System.out.println(Thread.currentThread().getName() + "::" + number);
            //通知
            condition.signalAll();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            lock.unlock();
        }
    }
}

public class LockDemo01 {
    
    
    public static void main(String[] args) {
    
    
        TShare tShare = new TShare();
        new Thread(() -> {
    
    
            for (int i = 0; i < 10; i++) {
    
    
                tShare.incr();
            }
        },"线程1").start();
        new Thread(() -> {
    
    
            for (int i = 0; i < 10; i++) {
    
    
                tShare.decr();
            }
        },"线程2").start();
    }
}

在这里插入图片描述

四 线程之间的定制化通信

在这里插入图片描述

package new_course.chp2.increment_decrement;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Created by Lin Weihong
 * @date on 2022/6/1 20:00
 * 线程之间的定制化通信
 * AA打印5次 --> BB打印10次 --> CC打印15次
 * 重复10轮
 */
//资源类
class LShare {
    
    
    //标志位 1:AA 2:BB 3:CC
    private int flag = 1;
    //创建Lock锁
    private final Lock lock = new ReentrantLock();
    //创建三个Condition
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();

    //操作方法
    public void print5(int loop) {
    
    
        //上锁
        lock.lock();
        try {
    
    
            //判断
            while (flag != 1) {
    
    
                //等待
                condition1.await();
            }
            //干活
            for (int i = 1; i <= 5; i++) {
    
    
                System.out.println(Thread.currentThread().getName() + "::" + i + ":轮数:" + loop);
            }
            //定制化,通知
            //修改标志位
            flag = 2;
            //只通知c2
            condition2.signal();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            lock.unlock();
        }
    }

    //操作方法
    public void print10(int loop) {
    
    
        //上锁
        lock.lock();
        try {
    
    
            //判断
            while (flag != 2) {
    
    
                //等待
                condition2.await();
            }
            //干活
            for (int i = 1; i <= 10; i++) {
    
    
                System.out.println(Thread.currentThread().getName() + "::" + i + ":轮数:" + loop);
            }
            //定制化,通知
            //修改标志位
            flag = 3;
            //只通知c3
            condition3.signal();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            lock.unlock();
        }
    }

    //操作方法
    public void print15(int loop) {
    
    
        //上锁
        lock.lock();
        try {
    
    
            //判断
            while (flag != 3) {
    
    
                //等待
                condition3.await();
            }
            //干活
            for (int i = 1; i <= 15; i++) {
    
    
                System.out.println(Thread.currentThread().getName() + "::" + i + ":轮数:" + loop);
            }
            //定制化,通知
            //修改标志位
            flag = 1;
            //只通知c2
            condition1.signal();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            lock.unlock();
        }
    }
}

public class LockDemo02 {
    
    
    public static void main(String[] args) {
    
    
        LShare lShare = new LShare();
        new Thread(() -> {
    
    
            for (int i = 1; i <= 10; i++) {
    
    
                lShare.print5(i);
            }
        }, "线程1").start();
        new Thread(() -> {
    
    
            for (int i = 1; i <= 10; i++) {
    
    
                lShare.print10(i);
            }
        }, "线程2").start();
        new Thread(() -> {
    
    
            for (int i = 1; i <= 10; i++) {
    
    
                lShare.print15(i);
            }
        }, "线程3").start();
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_48244108/article/details/125342534
今日推荐