多线程(Thread的类的运用-Runnable类的使用/多线程的注意点)

多线程

  • 是程序中执行的线程。Java虚拟机允许应用程序同时执行多个执行线程。

    每个线程都有优先权。 具有较高优先级的线程优先于优先级较低的线程执行。 每个线程可能也可能不会被标记为守护程序。 当在某个线程中运行的代码创建一个新的Thread对象时,新线程的优先级最初设置为等于创建线程的优先级,并且当且仅当创建线程是守护进程时才是守护线程。

    当Java虚拟机启动时,通常有一个非守护进程线程(通常调用某些指定类的名为main的方法)。 Java虚拟机将继续执行线程,直到发生以下任一情况:

    • 已经调用了Runtime类的exit方法,并且安全管理器已经允许进行退出操作。
    • 所有不是守护进程线程的线程都已经死亡,无论是从调用返回到run方法还是抛出超出run方法的run

    创建一个新的执行线程有两种方法。 一个是将一个类声明为Thread的子类。 这个子类应该重写run类的方法Thread 。 然后可以分配并启动子类的实例。 例如,计算大于规定值的素数的线程可以写成如下:


    class PrimeThread extends Thread { long minPrime; PrimeThread(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . } }


    然后,以下代码将创建一个线程并启动它运行:

    PrimeThread p = new PrimeThread(143); p.start();

    另一种方法来创建一个线程是声明实现类Runnable接口。 那个类然后实现了run方法。 然后可以分配类的实例,在创建Thread时作为参数传递,并启动。 这种其他风格的同一个例子如下所示:


    class PrimeRun implements Runnable { long minPrime; PrimeRun(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . } }


    然后,以下代码将创建一个线程并启动它运行:

    PrimeRun p = new PrimeRun(143); new Thread(p).start();

    每个线程都有一个用于识别目的的名称。 多个线程可能具有相同的名称。 如果在创建线程时未指定名称,则会为其生成一个新名称。

    除非另有说明,否则将null参数传递给null中的构造函数或方法将导致抛出NullPointerException

    要点

    1.线程就是独立的执行路径;

    2.在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;main()称之为主线程,为系统的入口,用于执行整个程序;

    3.在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能认为的干预的。

    4.对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;线程会带来额外的开销,如cpu调度时间,并发控制开销。

    5.每个线程在自己的工作内存交互,内存控制不当会造成数据不一致.

    img

    继承Thread类

    img

    实现编码

    ``

    package wang.com.demo01;
    
    import org.apache.commons.io.FileUtils;
    
    import java.io.File;
    import java.io.IOException;
    import java.net.URL;
    //联系Thread,实现多线程下载图片
    public class TestThread02 extends Thread{
        private String url;//地址图片的网络
        private String name;//图片的名字
    
    //通过构造器传参数
        public TestThread02(String url,String name) {
            this.url = url;
            this.name = name;
        }
    //下载图片的执行体
        @Override
        public void run() {
            WebDownlonder webDownlonder = new WebDownlonder();
            webDownlonder.downlonder(url,name);
            System.out.println("下载了文件,文件名为"+name);
        }
    
        public static void main(String[] args) {
            TestThread02 t1 = new TestThread02("http://www.kuangstudy.com/assert/course/c1/01.jpg","1.jpg");
            TestThread02 t2 = new TestThread02("http://www.kuangstudy.com/assert/course/c1/02.jpg","2.jpg");
            TestThread02 t3 = new TestThread02("http://www.kuangstudy.com/assert/course/c1/03.jpg","3.jpg");
    
            t1.start();
            t2.start();
            t3.start();
        }
    }
    //下载器
    class WebDownlonder{
        //下载方法
        public void downlonder(String url,String name){
            try {
                FileUtils.copyURLToFile(new URL(url),new File(name));
            } catch (IOException e) {
                System.out.println("捕获错误,下载错误");
            }
        }
    }
    

Runnable接口

  • 另一种方法来创建一个线程是声明实现类Runnable接口。 那个类然后实现了run方法。 然后可以分配类的实例,在创建Thread时作为参数传递,并启动。 这种其他风格的同一个例子如下所示:


    class PrimeRun implements Runnable { long minPrime; PrimeRun(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . } }


    然后,以下代码将创建一个线程并启动它运行:

    PrimeRun p = new PrimeRun(143); new Thread(p).start();

    每个线程都有一个用于识别目的的名称。 多个线程可能具有相同的名称。 如果在创建线程时未指定名称,则会为其生成一个新名称。

    实现代码

package wang.com.demo01;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

public class TestRunnable02 implements Runnable{
    private String url;//图片的网络地址
    private String name;//图片的名字

    //通过构造器传参数
    public TestRunnable02(String url,String name) {
        this.url = url;
        this.name = name;
    }
    //下载图片的执行体
    @Override
    public void run() {
        WebDownlonder webDownlonder = new WebDownlonder();
        webDownlonder.downlonder(url,name);
        System.out.println("下载了文件,文件名为"+name);
    }

    public static void main(String[] args) {
        TestThread02 t1 = new TestThread02("http://www.kuangstudy.com/assert/course/c1/01.jpg","1.jpg");
        TestThread02 t2 = new TestThread02("http://www.kuangstudy.com/assert/course/c1/02.jpg","2.jpg");
        TestThread02 t3 = new TestThread02("http://www.kuangstudy.com/assert/course/c1/03.jpg","3.jpg");

        new Thread(t1).start();
        new Thread(t2).start();
        new Thread(t3).start();
    }
}

并发初识

``

package wang.com.demo01;
//多线程实现同一个对象
//抢票例子
//发现问题:多个线程操作同一个资源的情况下,资源不安全,数据紊乱.
public class TestThread implements Runnable{

   private int num = 10;


    @Override
    public void run() {
        while (true){
            if(num<=0)
                break;
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                System.out.println("睡眠失败");
            }
            System.out.println(Thread.currentThread().getName()+"抢到了第"+num--+"票");
        }
    }

    public static void main(String[] args) {

        TestThread testThread = new TestThread();

        new Thread(testThread,"王浩").start();
        new Thread(testThread,"汪磊").start();
        new Thread(testThread,"阿彬").start();
    }
}

龟兔赛跑

``

package wang.com.demo01;
//龟兔赛跑
public class Race implements Runnable {
    //胜利者
    private static String winner;
    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            //睡眠器使兔子睡眠
            if(Thread.currentThread().getName().equals("乌龟")&&i%10==0){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    System.out.println("捕获睡眠失败");
                }
            }
            //判断比赛是否结束
            Boolean flag = gameOver(i);
            if (flag) {
                break;
            }
            System.out.println(Thread.currentThread().getName() + "跑了" + i + "米");
        }
    }
    private boolean gameOver(int steps) {
        //判断有没有获胜者
        if (winner != null) {
            return true;
        } else {
            if (steps >= 100) {
                winner = Thread.currentThread().getName();
                System.out.println("获胜者是" + winner);
                return true;
            }
        }
        return false;
    }
    //一个进程实现多个对像的处理
    public static void main(String[] args) {
        Race race = new Race();

        new Thread(race, "兔子").start();
        new Thread(race, "乌龟").start();
    }
}

实现Callable接口(了解)

``

package wang.com.demo02;


import org.apache.commons.io.FileUtils;
import wang.com.demo01.TestThread02;
import wang.com.demo02.WebDownlonder;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

public class TestCallable implements Callable<Boolean>{
    private String url;//图片的网络地址
    private String name;//图片的名字

    //通过构造器传参数
    public TestCallable(String url,String name) {
        this.url = url;
        this.name = name;
    }
    //下载图片的执行体
    @Override
    public Boolean call() {
        WebDownlonder webDownlonder = new WebDownlonder();
        webDownlonder.downlonder(url,name);
        System.out.println("下载了文件,文件名为"+name);
        return true;
    }

    public static void main(String[] args) throws ExecutionException,InterruptedException {
        TestCallable t1 = new TestCallable("http://www.kuangstudy.com/assert/course/c1/01.jpg","1.jpg");
        TestCallable t2 = new TestCallable("http://www.kuangstudy.com/assert/course/c1/02.jpg","2.jpg");
        TestCallable t3 = new TestCallable("http://www.kuangstudy.com/assert/course/c1/03.jpg","3.jpg");

        //创建执行服务
        ExecutorService ser = Executors.newFixedThreadPool(3);

        //提交执行
        Future<Boolean> r1 = ser.submit(t1);
        Future<Boolean> r2 = ser.submit(t2);
        Future<Boolean> r3 = ser.submit(t3);
        //获取结果
        boolean rs1 = r1.get();
        boolean rs2 = r2.get();
        boolean rs3 = r3.get();

        System.out.println(rs1);
        System.out.println(rs2);
        System.out.println(rs3);

        //关闭服务
        ser.shutdownNow();
    }
}
class WebDownlonder{
    //下载方法
    public void downlonder(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            System.out.println("捕获错误,下载错误");
        }
    }
    }
image-20201116162731950

静态代理模式

静态代理模式总结:

1.真实对象与代理对象都实现同一个接口
2.代理对象代理真实对象

好处:

1.静态的代理对象可以实现更多的方法
2.真实的对象可以专注与自己的事情

``

package wang.com.demo03;
//静态代理模式总结:
//1.真实对象与代理对象都实现同一个接口
//2.代理对象代理真实对象

//好处:
//静态的代理对象可以实现更多的方法
//真实的对象可以专注与自己的事情
public class StacticProxy {
    public static void main(String[] args) {

        //静态代理模式与Thread实现Runnable接口是一样的
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("年轻人,耗子尾汁");
            }
        }).start();

        //可以说多线程就是一种静态代理模式
        new WeddingCompany(new You()).HappyMarry();
    }
}
//提供一个Marry接口
interface Marry{

    void HappyMarry();
}
//真实对象实现接口
class You implements Marry{
    @Override
    public void HappyMarry() {
        System.out.println("今天王林彬结婚了");
    }
}
//代理对象实现接口
class WeddingCompany implements Marry{
    private Marry target;
    //代理对象代理谁?--->通过真实对象传递来的真实对象
    public WeddingCompany(Marry target) {
        this.target = target;
    }

    @Override
    public void HappyMarry() {
        before();
        this.target.HappyMarry();//通过构造函数传进来的真实对像
        after();
    }

    private void after() {
        System.out.println("发现孩子不是自己的");
    }
    private void before() {
        System.out.println("王林彬未婚先孕");
    }

}

Lambda表达式(个人感觉作用不大,代码可读性差)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OaDZJpgU-1605706824728)(file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C\T00_B_]K[ET@1BCD`0JTCYX.png)]

局部内部类:main中的类

静态内部类:class中的static的类

匿名内部类:没有名字的类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DamrfWtD-1605706824731)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201116200155223.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ypgT2h25-1605706824732)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201116200241577.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WXrfp9SG-1605706824734)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201116200317262.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ckebyLnX-1605706824735)(file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C\R726696VX[IH`L0J63M[B6K.png)]

线程停止(通过自己设置的标识符来决定线程是否要停止)

``

package wang.com.demo03;
public class TestStop implements Runnable {
    //1.设置一个标识位
    private Boolean flag = true;

    @Override
    public void run() {
        int i=0;
        while(flag) {
            System.out.println("run>>>..."+i++);
        }
    }
    //2.改变标识位
    void Stop(){
        this.flag = false;
        System.out.println("线程结束");
    }

    public static void main(String[] args) {
        TestStop testStop = new TestStop();
        new Thread(testStop).start();

        for (int i = 0; i < 100; i++) {
            System.out.println("main..."+i);
            //3.调用stop标志位让线程停止
            if(i == 66){
                testStop.Stop();
                System.out.println("结束了");
            }
        }
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XAxkNz6f-1605706824736)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201118143521922.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m22y3rF6-1605706824737)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201118143602956.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-urIAyOSx-1605706824738)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201118143651888.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N1upUQzP-1605706824738)(file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C{GDN_R`SP]U769BKJU${354.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4P7MV7TR-1605706824739)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201118143743020.png)]

线程休眠( Thread.Sleep() )

线程休眠
sleep(时间)指定当前线程阻塞的毫秒数;
sleep存在异常InterruptedException;
sleep时间达到后线程进入就绪状态;
sleep可以模拟网络延时,倒计时等。
每一个对象都有一个锁,sleep不会释放锁;


``[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9MiWVnVj-1605706824740)(file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C\L00L5Y7F3{4B$U9VY[GS)]2R.png)

package wang.com.demo03;

import java.text.SimpleDateFormat;
import java.util.Date;

//模拟倒计时
public class TestSleep02{
    public static void main(String[] args) {
        Date startTime = new Date(System.currentTimeMillis());//获取系统的当前时间
        while (true){
            try {
                Thread.sleep(1000);

                System.out.println(new SimpleDateFormat("HH,mm,ss").format(startTime));
                startTime = new Date(System.currentTimeMillis());//获取系统的当前时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

        //打印当前系统时间


        /*
        private static void tenDown() throws InterruptedException {
        //模拟倒计时
        int num = 10;

        for (int i = 10; i > 0; i--) {
            Thread.sleep(1000);
            System.out.println(i);
        }


         */
    }

线程礼让( Thread.yield() )

![img](file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C\G42Y2_EBPZAJHW_P7PFCV.png)

``

package wang.com.demo03;

public class TestYield {
    public static void main(String[] args) {
        MyYield myYield = new MyYield();

        new Thread(myYield,"a").start();
        new Thread(myYield,"b").start();
    }

}
class MyYield implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"线程开始");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"线程结束");
    }
}

线程插队( Thread.join() )

package wang.com.demo03;

public class TestJoin implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 300; i++) {
            System.out.println("VIP来了"+i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        //将testJoin给Thread代理
        TestJoin testJoin = new TestJoin();
        Thread thread = new Thread(testJoin);
        thread.start();

        for (int i = 0; i < 500; i++) {
            if(i==200) {
                thread.join();//插队
            }
            System.out.println("main"+i);
        }

    }
}

![img](file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C\S6424]P@HTSM_YB`Q2Q}N.png)

观察线程状态( thread.start(); )

  • public static enum Thread.State
    extends Enum<Thread.State>
    

    线程状态。线程可以处于以下状态之一:

    • NEW
      尚未启动的线程处于此状态。
    • RUNNABLE
      在Java虚拟机中执行的线程处于此状态。
    • BLOCKED
      被阻塞等待监视器锁定的线程处于此状态。
    • WAITING
      正在等待另一个线程执行特定动作的线程处于此状态。
    • TIMED_WAITING
      正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。
    • TERMINATED
      已退出的线程处于此状态。

    一个线程可以在给定时间点处于一个状态。 这些状态是不反映任何操作系统线程状态的虚拟机状态。

    • 从以下版本开始:

      • Enum Constant and Description
        BLOCKED 一个线程的线程状态阻塞等待监视器锁定。
        NEW 线程尚未启动的线程状态。
        RUNNABLE 可运行线程的线程状态。
        TERMINATED 终止线程的线程状态。
        TIMED_WAITING 具有指定等待时间的等待线程的线程状态。
        WAITING 等待线程的线程状态

      ``

      package wang.com.demo03;
      
      public class TestState {
          public static void main(String[] args) throws InterruptedException {
              Thread thread = new Thread(() -> {
                  for (int i = 0; i < 5; i++) {
                      try {
                          Thread.sleep(1000);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      System.out.println("/");
                  }
              });
              Thread.State state = thread.getState();
              System.out.println(state);//new
      
              thread.start();//runnable
              state = thread.getState();
              System.out.println(state);
      
              while (state != Thread.State.TERMINATED) {
                  Thread.sleep(1000);
                  state = thread.getState();
                  System.out.println(state);
      
              }
          }
      }
      

线程的优先级(priority)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3zChiPrw-1605706824740)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201118165400293.png)]

``

package wang.com.demo03;
//测试线程都优先级
public class TestPriority{
    public static void main(String[] args) {
        //主程序为默认优先级
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());

        MyPriority myPriority = new MyPriority();

        Thread t1 = new Thread(myPriority);
        Thread t2 = new Thread(myPriority);
        Thread t3 = new Thread(myPriority);
        Thread t4 = new Thread(myPriority);
        Thread t5 = new Thread(myPriority);
        Thread t6 = new Thread(myPriority);
        Thread t7 = new Thread(myPriority);
        //设置优先级//由程序自己决定
        t1.start();

        //自己设置优先级
        t2.setPriority(1);
        t2.start();

        t3.setPriority(3);
        t3.start();

        t4.setPriority(6);
        t4.start();

        t5.setPriority(2);
        t5.start();

        t6.setPriority(8);
        t6.start();

        t7.setPriority(4);
        t7.start();

    }

}
class MyPriority implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
    }
}

守护线程(daemon)

``

package wang.com.demo03;

public class TestDaemon {
    public static void main(String[] args) {
        God god = new God();
        Yyou you = new Yyou();
        Thread thread = new Thread(god);
        thread.setDaemon(true);//默认false为用户线程,正常的线程多为用户线程

        thread.start();//上帝线程启动

        new Thread(you).start();

    }
}
class God implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("上帝会永远守护你的");
        }
    }
}
class Yyou implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("你一生都是开心的活着的");
        }
        System.out.println("Bye  world");
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ealZc3b8-1605706824741)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201118182104019.png)]

线程同步(三大不安全案例)

案例一

``

package wang.com.syn;

public class UnsafeBuyTicket {
    public static void main(String[] args) {
        BuyTicket station = new BuyTicket();

        //多个对像来抢票
        new Thread(station,"王浩").start();
        new Thread(station,"阿彬").start();
        new Thread(station,"汪磊").start();
    }

}
//买票的类
class BuyTicket implements Runnable{
    //设置票数
    private int TicketNums = 10;
    //设置外部标志
    private  Boolean flag = true;

    @Override
    public void run() {
        while(flag){
            buy();
        }
    }
    //买票的方法
    private void buy(){
        if(TicketNums < 0){
            flag = false;
            return;
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"拿到了第"+TicketNums-- +"张票");

    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WZ59ZhsJ-1606532453217)(file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C\WRTO[Y[}0SH`@1H_1F6S182.png)]

案例二

``

package wang.com.syn;

public class UnsafeBank {
    public static void main(String[] args) {
        Account account = new Account(100,"结婚基金");

        Drawing you = new Drawing(account,50,"你");
        Drawing GrilFriend = new Drawing(account,100,"GrilFriend");

        you.start();
        GrilFriend.start();
    }
}
class Account {
    int money;
    String name;

    public Account(int money, String name) {
        this.money = money;
        this.name = name;
    }
}
class Drawing extends Thread {
    int DrawingMoney;
    Account account;
    int NowMoney;

    public Drawing(Account account, int DrawingMoney, String name){
        super(name);
        this.account = account;
        this.DrawingMoney = DrawingMoney;
    }
    @Override
    public void run() {
        if(account.money - DrawingMoney < 0){
            System.out.println(Thread.currentThread().getName()+"钱不够,sorry");
            return;
        }
        //sleep可以放大问题的发生性
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        account.money = account.money - DrawingMoney;
        NowMoney = NowMoney + DrawingMoney;
        System.out.println(Thread.currentThread().getName()+"账户余额为"+account.money);
        System.out.println(Thread.currentThread().getName()+"手上的现金为"+NowMoney);
    }
}

案例三

``

package wang.com.syn;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;

public class UnsafeList {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}

同步方法及同步块(synchronized) 注:synchronized 同步方法,锁的是this

public synchronized void method(int args){}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mfKphSie-1606532453221)(file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C()]GJZZVCM@[97PY]KaTeX parse error: Expected 'EOF', got '}' at position 3: NE}̲~4.png)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jh7UTCnH-1606532453222)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201122144622626.png)]

synchronized(Obj){ }

案例1

``

package wang.com.syn;
//线程安全出现了负数

public class UnsafeBuyTicket {
    public static void main(String[] args) {
        BuyTicket station = new BuyTicket();

        //多个对像来抢票
        new Thread(station,"王浩").start();
        new Thread(station,"阿彬").start();
        new Thread(station,"汪磊").start();
    }

}
//买票的类
class BuyTicket implements Runnable{
    //设置票数
    private int TicketNums = 10;
    //设置外部标志
    private  Boolean flag = true;

    @Override
    public void run() {
        while(flag){
            buy();
        }
    }
    //买票的方法
    //synchronized  同步方法,锁的是this
    private synchronized void buy(){
        if(TicketNums < 1){
            flag = false;
            return;
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"拿到了第"+TicketNums-- +"张票");

    }
}

案例2

``

package wang.com.syn;

public class UnsafeBank {
    public static void main(String[] args) {
        Account account = new Account(100,"结婚基金");

        Drawing you = new Drawing(account,50,"你");
        Drawing GrilFriend = new Drawing(account,100,"GrilFriend");

        you.start();
        GrilFriend.start();
    }
}
class Account {
    int money;
    String name;

    public Account(int money, String name) {
        this.money = money;
        this.name = name;
    }
}
class Drawing extends Thread {
    int DrawingMoney;
    Account account;
    int NowMoney;

    public Drawing(Account account, int DrawingMoney, String name){
        super(name);
        this.account = account;
        this.DrawingMoney = DrawingMoney;
    }
    @Override
    public void run() {
    synchronized(account){
       
            if(account.money - DrawingMoney < 0){
                System.out.println(Thread.currentThread().getName()+"钱不够,sorry");
                return;
            }
            //sleep可以放大问题的发生性
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            account.money = account.money - DrawingMoney;
            NowMoney = NowMoney + DrawingMoney;
            System.out.println(Thread.currentThread().getName()+"账户余额为"+account.money);
            System.out.println(Thread.currentThread().getName()+"手上的现金为"+NowMoney);
    }
    
    }
}

案例3

``

package wang.com.syn;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;

public class UnsafeList {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                synchronized(list) {
                    list.add(Thread.currentThread().getName());
                }
            }).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}

JUC安全类型集合(CopyOnWriteArrayList)

测试线程安全的类

``

package wang.com.syn;

import java.util.concurrent.CopyOnWriteArrayList;

public class Juc {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}

死锁

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BUzGk5Sk-1606532453224)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201122160714216.png)]

![img](file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C\VY$D$E[P6EO7]5DG0XE}F.png)

``

package wang.com.syn;

public class DeadLock {
    public static void main(String[] args) {
        Makeup g1 = new Makeup(0,"王浩");
        Makeup g2 = new Makeup(1,"汪磊");
        g1.start();
        g2.start();
    }
}
//口红
class Lipstick{

}
//镜子
class Mirror{

}
class Makeup extends Thread {
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();

    int choice;
    String girlName;

    Makeup(int choice, String girlName) {
        this.choice = choice;
        this.girlName = girlName;
    }

    @Override
    public void run() {
        try {
            makeup();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void makeup() throws InterruptedException {
        if (choice == 0) {
            synchronized (lipstick) {
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + "口红的锁");
                synchronized (mirror) {
                    System.out.println(Thread.currentThread().getName() + "镜子的锁");
                }
            }
        }else{
                synchronized (mirror) {
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName() + "镜子的锁");
                    synchronized (lipstick) {
                        System.out.println(Thread.currentThread().getName() + "口红的锁");
                    }
                }
            }
        }
    }

Lock锁

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QmQNpzT2-1606532453225)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201122164352524.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-URxkbBj2-1606532453226)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201122164417068.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EIqWteXe-1606532453226)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201122164451732.png)]

演示代码

``

package wang.com.syn;

import java.util.concurrent.locks.ReentrantLock;

public class TestLock {
    public static void main(String[] args) {
        TestLock2 testLock2 = new TestLock2();

        new Thread(testLock2,"1").start();
        new Thread(testLock2,"2").start();
        new Thread(testLock2,"3").start();
    }
}
class TestLock2 implements Runnable{
    private int ticketNums = 10;
    private final ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
        try{
            lock.lock();
            while (true){
                if(ticketNums > 0){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(ticketNums--);
                }else{
                    break;
                }
            }
        }finally {
            lock.unlock();
        }


    }
}

生产者消费者问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hz7dKJaL-1606532453227)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201124090034272.png)]

![img](file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C\L4_GMNC@CECD117F9A}SG.png)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8qn8tj5t-1606532453228)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201124090107289.png)]

管程法

synchronized可以阻止并发更新同一个共享资源,实现同步.
但不能来实现不同线程之间的消息传递(即不能实现线程间的通信)

解决方法:
wait() 可以使线程一直等待,直到其它线程通知,与sleep不同,会释放锁.

notifyAll() 可以唤醒同一个对象上所以调用wait()方法的线程,优先级别高的线程优先调度.

``

package wang.com.syn;
//测试:生产者消费者模型,管程法
//生产者 消费者 产品 缓冲区
public class TestPC {
    public static void main(String[] args) {
        SynContainer Container = new SynContainer();
        //让生产者,消费者同时生产
        new Productor(Container).start();
        new Consumer(Container).start();
    }
}
//生产者
class Productor extends Thread{
    SynContainer Container;
    public Productor(SynContainer Container){
        this.Container = Container;
    }
    //生产
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            Container.push(new Chicken(i));
            System.out.println("生产了"+i+"只鸡");
        }
    }
}
//消费者
class Consumer extends Thread{
    SynContainer Container;
    public Consumer(SynContainer Container){
        this.Container = Container;
    }
    //消费
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消费了"+Container.pop().id+"只鸡");
        }
    }
}
//产品
class Chicken{
    int id;
    //给产品id赋值
    public Chicken(int id) {
        this.id = id;
    }
}
//缓冲区
class SynContainer{
    //需要一个容器
    Chicken[] chickens = new Chicken[10];
    //计数器
    int count=0;
    //生产者生产
    public synchronized void push(Chicken chicken){
        //如果容器满了,等待消费者消费
        if(count==chickens.length){
            //消费者消费,生产者停止
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //否则生产者也生产
        chickens[count] = chicken;
        count++;

        this.notifyAll();
    }
    //消费者消费
    public synchronized Chicken pop(){
        //判断能否消费
        if(count==0){
            //消费者停止,生产者生产
            try {
                //让该线程保持等待,直到有其它线程来通知
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果可以消费
        count--;
        Chicken chicken = chickens[count];
        //唤醒该对象所被等待的线程
        this.notifyAll();
        return chicken;
    }
}

信号灯法

``

package wang.com.syn;

public class TestPc2 {
    public static void main(String[] args) {
        TV tv = new TV();
        new Player(tv).start();
        new Watcher(tv).start();
    }
}
//演员表演--生产者
class Player extends Thread{
    TV tv;
    public Player(TV tv){
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if(i%2==0){
                this.tv.play("浩哥的幸福生活播放中:");
            }else{
                this.tv.play("浩哥打炮中:");
            }
        }
    }
}
//观众观看--消费者
class Watcher extends Thread{
    TV tv;
    public Watcher(TV tv){
        this.tv = tv;
    }

    @Override
    public void run() {
        this.tv.watch();
    }
}
//产品--TV
class TV{
    //节目名
    String voice;
    Boolean flag = true;
    //T时生产者生产,消费者停止
    //F时生产者停止,消费者观看

    //演员表演--即生产者生产
    public synchronized void play(String voice){
        if(!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("演员表演了:"+voice);
        this.voice = voice;
        this.notifyAll();
    }
    //观众观看--即消费者消费
    public synchronized void watch(){
        if(flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("观众观看了:"+voice);
        this.notifyAll();
    }

}

线程池

ExecutorService:真正的线程池接口.常见子类ThreadPoolExecutor

void execute(Runnable command):执行任务/命令,没有返回值,一般用来执行Runnable

Futuresubmit(Callabletask):执行任务,有返回值,一般用来执行Callable

void shutdown():关闭连接池

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QtzlKiZf-1606532453228)(file:///C:\Users\whl151885\Documents\Tencent Files\2076312724\Image\C2C\6ZDVMWWKA{~{F@NU][4I%$5.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iWDebqm0-1606532453229)(C:\Users\whl151885\AppData\Roaming\Typora\typora-user-images\image-20201127105952555.png)]

``

package wang.com.syn;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestPool {
    public static void main(String[] args) {
        //1.创建服务,创建线程池
        //newFixedThreadPool(10):设置线程池的大小
        ExecutorService service = Executors.newFixedThreadPool(10);

        //2.执行线程
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());

        //3.关闭线程池服务
        service.shutdown();
    }
}
class MyThread implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

多线程总结

``

package wang.com.syn;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class ThreadNew {
    public static void main(String[] args) {
        new MyThread01().start();
        MyThread02 myThread02 = new MyThread02();
        new Thread(myThread02).start();

        FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread03());
        new Thread(futureTask).start();

        try {
            Integer integer = futureTask.get();
            System.out.println(integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
//1.继承Thread方法
class MyThread01 extends Thread{
    @Override
    public void run() {
        System.out.println("MyThread01");
    }
}

//2.实现Runnable类
class MyThread02 implements Runnable{
    @Override
    public void run() {
        System.out.println("MyThread02");
    }
}
//3.实现Callable类
class MyThread03 implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        System.out.println("MyThread03");
        return 111;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三横同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值