JAVA多线程

时间:2021-03-07 00:05:42   收藏:0   阅读:32

JAVA多线程

main()主线程

创建线程

单继承局限性
避免单继承局限性, 灵活  方便同一个对象被多个线程调用
package com.cyz.demo01;
?
public class TestThread1 extends Thread {
?
   @Override
   public void run() {
       //run方法线程体
       for (int i = 0; i < 20; i++) {
           System.out.println("我在看代码!"+i);
      }
  }
?
   public static void main(String[] args) {
       //main线程. 主线程
?
       //创建一个线程对象
       TestThread1 testThread1 = new TestThread1();
?
       //直接调用run()会先执行run()
       //testThread1.run();
       //调用start() 方法开启线程   由cpu调度
       testThread1.start();
?
       for (int i = 0; i < 200; i++){
           System.out.println("我在学习多线程!"+i);
      }
  }
}
?
package com.cyz.demo01;
?
import org.apache.commons.io.FileUtils;
?
import java.io.File;
import java.io.IOException;
import java.net.URL;
?
?
//练习Thread 实现多线程同步下载图片
public class TestThread2 extends Thread {
?
   private String url; //网络图片地址
   private String name;//保存的文件名
?
?
   public TestThread2(String url, String name){
       this.url=url;
       this.name=name;
  }
?
   //下载图片线程的执行体
   @Override
   public void run() {
       WebDownloader webDownloader = new WebDownloader();
       webDownloader.downloader(url,name);
       System.out.println("下载了文件名为: "+name);
  }
?
   public static void main(String[] args) {
       TestThread2 t1 = new TestThread2("https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2488102644,4095521058&fm=26&gp=0.jpg", "logo1.jpg");
       TestThread2 t2 = new TestThread2("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1590680125925&di=f56419579f92cece858fb47eb8d3b831&imgtype=0&src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20180703%2F4669d3d7dec3494ebcd87f342ba9dc1b.jpeg", "logo2.jpg");
       TestThread2 t3 = new TestThread2("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1590680125925&di=1ea492a995c25217247505465f23309a&imgtype=0&src=http%3A%2F%2Fa.hiphotos.baidu.com%2Fzhidao%2Fpic%2Fitem%2F9358d109b3de9c82713ecb576c81800a18d8438a.jpg", "logo3.jpg");
?
       t1.start();
       t2.start();
       t3.start();
  }
}
?
class WebDownloader{
?
   //下载方法
   public void downloader(String url, String name){
       try {
           FileUtils.copyURLToFile(new URL(url), new File(name));
      } catch (IOException e) {
           e.printStackTrace();
           System.out.println("IO异常,downloader方法出现异常");
      }
  }
}
?
package com.cyz.demo01;
?
//方式2 实现Runnable接口, 重写run方法
   //需要Thread代理
public class TestThread3 implements Runnable {
?
   @Override
   public void run() {
       //run方法线程体
       for (int i = 0; i < 20; i++) {
           System.out.println("我在看代码!"+i);
      }
  }
?
   public static void main(String[] args) {
       TestThread3 testThread3 = new TestThread3();
?
       //代理 传入实现接口的对象
       new Thread(testThread3).start();
?
       for (int i = 0; i < 200; i++) {
           System.out.println("我在学习多线程!"+i);
      }
?
  }
}
?
package com.cyz.demo01;
?
//有并发问题 同时会拿到相同的数字
public class TestThread4 implements Runnable {
?
  //票数
  private int ticketNums = 10;
?
  @Override
  public void run() {
      while (true){
          //延时
          try {
              Thread.sleep(200);
              if (ticketNums <= 0){
                  break;
              }
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
?
          System.out.println(Thread.currentThread().getName()+" 拿到了第"+ ticketNums-- +" 张票");
      }
  }
?
  public static void main(String[] args) {
      TestThread4 ticket = new TestThread4();
?
      new Thread(ticket,"小名").start();
      new Thread(ticket,"老师").start();
      new Thread(ticket,"黄牛").start();
  }
}
?

龟兔赛跑案例

package com.cyz.demo01;
?
import sun.awt.windows.ThemeReader;
?
//模拟龟兔赛跑
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(1);
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }
          }
?
           //判断比赛是否结束
           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 is " + winner);
               return true;
          }
      }
?
?
       return false;
  }
?
   public static void main(String[] args) {
       Race race = new Race();
?
       new Thread(race,"兔子").start();
       new Thread(race,"乌龟").start();
  }
}
?
package com.cyz.demo02;
?
import org.apache.commons.io.FileUtils;
?
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
?
public class TestCallable implements Callable {
   private String url; //网络图片地址
   private String name;//保存的文件名
?
?
   public TestCallable(String url, String name){
       this.url=url;
       this.name=name;
  }
?
   //下载图片线程的执行体
   @Override
   public Boolean call() {
       WebDownloader webDownloader = new WebDownloader();
       webDownloader.downloader(url,name);
       System.out.println("下载了文件名为: "+name);
       return true;
  }
?
   public static void main(String[] args) throws ExecutionException, InterruptedException {
       TestCallable c1 = new TestCallable("https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2488102644,4095521058&fm=26&gp=0.jpg", "logo1.jpg");
       TestCallable c2 = new TestCallable("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1590680125925&di=f56419579f92cece858fb47eb8d3b831&imgtype=0&src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20180703%2F4669d3d7dec3494ebcd87f342ba9dc1b.jpeg", "logo2.jpg");
       TestCallable c3 = new TestCallable("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1590680125925&di=1ea492a995c25217247505465f23309a&imgtype=0&src=http%3A%2F%2Fa.hiphotos.baidu.com%2Fzhidao%2Fpic%2Fitem%2F9358d109b3de9c82713ecb576c81800a18d8438a.jpg", "logo3.jpg");
?
       //创建执行服务
       ExecutorService ser = Executors.newFixedThreadPool(3);
?
       //提交执行
       Future<Boolean> r1 = ser.submit(c1);
       Future<Boolean> r2 = ser.submit(c2);
       Future<Boolean> r3 = ser.submit(c3);
       //获得结果
       boolean result1 = r1.get();
       boolean result2 = r2.get();
       boolean result3 = r3.get();
       //关闭服务
       ser.shutdownNow();
?
       System.out.println("result1"+result1);
       System.out.println("result2"+result2);
       System.out.println("result3"+result3);
  }
?
}
?
class WebDownloader{
?
   //下载方法
   public void downloader(String url, String name){
       try {
           FileUtils.copyURLToFile(new URL(url), new File(name));
      } catch (IOException e) {
           e.printStackTrace();
           System.out.println("IO异常,downloader方法出现异常");
      }
  }
}
?

静态代理模式

package com.cyz.demo03;

public class StaticProxy {

public static void main(String[] args) {
    WeddingCompany weddingCompany = new WeddingCompany(new You());
    weddingCompany.HappyMarry();
}

}

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("结婚前,布置现场");
}

}

new Thread(()->System.out.println("我爱你")).start();

new WeddingCompany(new You().HappyMarry();

Lambda表达式

(params) -> 表达式
    (params) -> 语句
    	(params) -> {}

前提

函数式接口

public inteface Runnable{
    public void run();
}

演化过程

package com.cyz.demo03;

public class TestLambda {
public static void main(String[] args) {
ILike like = new Like();
like.lambda();
}
}

//函数式接口
interface ILike{
void lambda();
}

//实现类
class Like implements ILike{

@Override
public void lambda() {
    System.out.println("I like lambda");
}

}

package com.cyz.demo03;

public class TestLambda {

    //静态内部类
    static class Like2 implements ILike{

        @Override
        public void lambda() {
            System.out.println("I like lambda2");
        }
    }

    public static void main(String[] args) {
        ILike like = new Like();
        like.lambda();

        like = new Like2();
        like.lambda();
    }
}

//函数式接口
interface ILike{
    void lambda();
}

//实现类
class Like implements ILike{

    @Override
    public void lambda() {
        System.out.println("I like lambda");
    }
package com.cyz.demo03;

public class TestLambda {

    //静态内部类
    static class Like2 implements ILike{

        @Override
        public void lambda() {
            System.out.println("I like lambda2");
        }
    }

    public static void main(String[] args) {
        ILike like = new Like();
        like.lambda();

        like = new Like2();
        like.lambda();

        //局部内部类
        class Like3 implements ILike{

            @Override
            public void lambda() {
                System.out.println("I like lambda3");
            }
        }

        like = new Like3();
        like.lambda();
        
    }
}

//函数式接口
interface ILike{
    void lambda();
}

//实现类
class Like implements ILike{

    @Override
    public void lambda() {
        System.out.println("I like lambda");
    }
}


package com.cyz.demo03;

/**
 * com.cyz.demo03
 *
 * @author cyz
 * @create 2020/05/29 09-05
 */
public class TestLambda {

    //静态内部类
    static class Like2 implements ILike{

        @Override
        public void lambda() {
            System.out.println("I like lambda2");
        }
    }

    public static void main(String[] args) {
        ILike like = new Like();
        like.lambda();

        like = new Like2();
        like.lambda();

        //局部内部类
        class Like3 implements ILike{

            @Override
            public void lambda() {
                System.out.println("I like lambda3");
            }
        }

        like = new Like3();
        like.lambda();

        //匿名内部类
        like = new ILike(){

            @Override
            public void lambda() {
                System.out.println("I like lambda4");
            }
        };
        like.lambda();

    }
}

//函数式接口
interface ILike{
    void lambda();
}

//实现类
class Like implements ILike{

    @Override
    public void lambda() {
        System.out.println("I like lambda");
    }
}


package com.cyz.demo03;

public class TestLambda {

    //3. 静态内部类
    static class Like2 implements ILike{

        @Override
        public void lambda() {
            System.out.println("I like lambda2");
        }
    }

    public static void main(String[] args) {
        ILike like = new Like();
        like.lambda();

        like = new Like2();
        like.lambda();

        //4. 局部内部类
        class Like3 implements ILike{

            @Override
            public void lambda() {
                System.out.println("I like lambda3");
            }
        }

        like = new Like3();
        like.lambda();

        //5. 匿名内部类
        like = new ILike(){

            @Override
            public void lambda() {
                System.out.println("I like lambda4");
            }
        };
        like.lambda();

        //6. 用Lambda
        like = () -> {
            System.out.println("I like lambda5");
        };
        like.lambda();

    }
}

//1. 函数式接口
interface ILike{
    void lambda();
}

//2. 实现类
class Like implements ILike{

    @Override
    public void lambda() {
        System.out.println("I like lambda");
    }
}


例子

package com.cyz.demo03;

public class TestLambda2 {
public static void main(String[] args) {
ILove iLove = (int a) -> {
System.out.println(a);
};

    iLove.love(1);

    //简化
    //多参数 一个去掉参数类型, 就都去掉
    iLove = (a) -&gt;{
        System.out.println(a);
    };

    iLove.love(2);

    //在简化
	//多个参数必须有括号
    iLove = a -&gt;{
        System.out.println(a);
    };

    iLove.love(3);

    //在简化   前提:代码只有一行
    iLove = a -&gt; System.out.println(a);
    
    iLove.love(4);
}

}

interface ILove{
void love(int a);
}

线程转态

  1. 创建状态 (new)

  2. 就绪状态 (调用start()后)

  3. 阻塞状态 (调用 sleep, wait 或 同步锁时)

  4. 运行状态 (CPU调度)

  5. 死亡状态 (中断 或 结束)

线程方法

方法说明
setPrority(int newPriority) 更改线程优先级
static void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程体休眠
void join() 等待该线程终止
static void yield() 暂停当前正在执行的线程对象, 并执行其他线程
void interrupt() 中断线程, 别用这种方式
boolean isAlive() 测试线程是否处于活动状态

停止线程

  1. 建议线程正常停止 --->利用次数, 不建议死循环

  2. 建议使用标志位 ----> 设置一个标志位

  3. 不使用stop 或者 destroy 过时了

package com.cyz.demo04;

//测试stop
//1. 建议线程正常停止 --->利用次数, 不建议死循环
//2. 建议使用标志位 ----> 设置一个标志位
//3. 不使用stop 或者 destroy 过时了
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. 设置一个公开的方法停止线程 转换标志位
public void stop(){
    this.flag = false;
}

public static void main(String[] args) {
    TestStop stop = new TestStop();

    new Thread(stop).start();

    for (int i = 0; i &lt; 1000; i++){
        System.out.println("main"+i);
        if(i == 900){
            stop.stop();
            System.out.println("线程停止了");
        }
    }
}

}

Sleep

  1. 时间为毫秒数

  2. 存在异常InterruptedException

  3. 时间达到后线程进入就绪状态

  4. 模拟网络延时, 倒计时

  5. 每个对象都有一个锁, sleep不会释放锁

延时

package com.cyz.demo04;

/**

  • com.cyz.demo04

  • @author cyz

  • @create 2020/05/29 09-43
    */
    public class TestSleep implements Runnable{

    //票数
    private int ticketNums = 10;

    @Override
    public void run() {
    while (true){
    //延时
    try {
    Thread.sleep(200);
    if (ticketNums <= 0){
    break;
    }
    } catch (InterruptedException e) {
    e.printStackTrace();
    }

         System.out.println(Thread.currentThread().getName()+" 拿到了第"+ ticketNums-- +" 张票");
     }
    

    }

    public static void main(String[] args) {
    TestSleep ticket = new TestSleep();

     new Thread(ticket,"小名").start();
     new Thread(ticket,"老师").start();
     new Thread(ticket,"黄牛").start();
    

    }
    }

倒计时

package com.cyz.demo04;

public class testSleep2 {

public static void main(String[] args) {
       
    try {
        tenDown();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

public static void tenDown() throws InterruptedException {
    int num =10;
    while (true){
        Thread.sleep(1000);
        System.out.println(num--);
        if (num &lt;= 0){
            break;
        }
    }
}

}

模拟打印系统时间

package com.cyz.demo04;

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

public class testSleep2 {

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();
        }
    }
}

}

线程礼让 -yield

  1. 让当前正在执行的线程暂停, 但不阻塞

  2. 将线程运行状态转为就绪状态

  3. 让cpu重新调度, 礼让不一定成功, 得看cpu

package com.cyz.demo05;

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()+"线程停止执行");
}

}

线程强制执行-join

package com.cyz.demo06;

public class TestJoin implements Runnable {

@Override
public void run() {
    for (int i = 0; i &lt; 100; i++){
        System.out.println("线程Vip来了"+i);
    }
}

public static void main(String[] args) throws InterruptedException {
    TestJoin testJoin = new TestJoin();

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

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

}

观测线程状态

  1. NEW 尚未启动

  2. RUNNABLE 执行的线程

  3. BLOCKED 被阻塞等待监视器锁定的线程

  4. WAITING 正在等待另一个线程执行特定动作的线程

  5. TIMED_WAITING 正在等待另一个线程执行动作达到指定时间的的线程

  6. TERMINATED 已退出的线程

package com.cyz.demo07;

/**

  • com.cyz.demo07

  • @author cyz

  • @create 2020/05/29 10-06
    */
    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();
     state = thread.getState();
     System.out.println(state);//Run
    
     while(state != Thread.State.TERMINATED){//只要线程不终止, 就一直输出状态
         Thread.sleep(100);
         state = thread.getState();//更新状态
         System.out.println(state);
     }
    

    }
    }

线程优先级

改变优先级

package com.cyz.demo07;

public class TestPriority {

public static void main(String[] args) {
    System.out.println(Thread.currentThread().getName()+"----&gt;"+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);

    //先设置优先级在启动
    t1.start();

    t2.setPriority(1);
    t2.start();

    t3.setPriority(4);
    t3.start();

    t4.setPriority(Thread.MAX_PRIORITY);
    t4.start();


    //范围报错

// t5.setPriority(-1);
// t5.start();
//
// t6.setPriority(11);
// t6.start();

}

}

class MyPriority implements Runnable {

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

}

守护线程

package com.cyz.demo07;

//上帝守护你
public class TestDaemon {

public static void main(String[] args) {
    God god = new God();
    You you = new You();

    Thread thread = new Thread(god);
    thread.setDaemon(true);//默认是false 表示用户线程 正常的线程都是用户线程

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

    new Thread(you).start();

    //虽然守护线程是while 但是虚拟机不管守护线程 所以当用户线程执行完毕后, 虚拟机停止了 就不在执行线程了
}

}

//上帝
class God implements Runnable{

@Override
public void run() {
    while(true){
        System.out.println("上帝保佑你");
    }
}

}

//你
class You implements Runnable{

@Override
public void run() {
    for(int i = 0; i &lt; 365000; i++){
        System.out.println("活着");
    }
    System.out.println("goodbye! world");
}

}

线程的同步

队列和锁

同步

存在问题

  1. 一个线程持有锁会导致其他所有需要此锁的线程挂起;

  2. 在多线程竞争下, 加锁, 释放锁会导致比较多的上下文切换 和 调度延时 , 引起性能问题

  3. 如果一个优先级高的线程等待一个优先级低的线程释放锁, 会导致优先级倒置,引起性能问题

案例

package com.cyz.demo08;

//线程不安全的买票 有负数
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;
//标位
boolean flag = true;//外部停止方式

@Override
public void run() {
    //买票
    while(flag){
        try {
            buy();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

private void buy() throws InterruptedException {
    //判断是否有票
    if (ticketNums &lt;= 0){
        flag = false;
        return;
    }
    //模拟延时
    Thread.sleep(100);
    //买票
    System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);
}

}

package com.cyz.demo08;

//不安全的取钱
    //两个人去银行取钱  同一个账户
public class UnsafeBank {
    public static void main(String[] args) {
        //账户
        Account account = new Account(100,"基金");

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

        you.start();
        she.start();
    }
}

//账户
class Account{
    int money;//余额
    String name;//卡名

    public Account(int money, String name){
        this.money = money;
        this.name = name;
    }
}

//银行 模拟取款
class Drawing extends Thread{
    Account account;//账户
    //取了多少
    int drawingMoney;
    //现在手里有多少钱
    int nowMoeny;

    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()+"钱不够");
            return;
        }


        //sleep放大问题的发生性
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //卡内余额 = 余额 - 你取的钱
        account.money = account.money - drawingMoney;
        //你手里的钱
        nowMoeny = nowMoeny + drawingMoney;

        System.out.println(account.name+"余额为:"+account.money);
        //Thread.currentThread().getName() = this.getName()
        System.out.println(this.getName()+"手里的钱:"+nowMoeny);
    }
}
package com.cyz.demo08;

import java.util.ArrayList;
import java.util.List;

//线程不安全的集合   没有存到10000个
public class UnsafeList {
    public static void main(String[] args) throws InterruptedException {
        List<String> list = new ArrayList<String>();
        for (int i= 0; i < 10000; i++){
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        Thread.sleep(3000);
        System.out.println(list.size());
    }
}

同步方法和同步块

package com.cyz.demo08;

//线程不安全的买票 有负数
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;
//标位
boolean flag = true;//外部停止方式

@Override
public void run() {
    //买票
    while(flag){
        try {
            buy();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

//synchronized 同步  锁this
private synchronized void buy() throws InterruptedException {
    //判断是否有票
    if (ticketNums &lt;= 0){
        flag = false;
        return;
    }
    //模拟延时
    Thread.sleep(100);
    //买票
    System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);
}

}

package com.cyz.demo08;
 
//不安全的取钱
//两个人去银行取钱  同一个账户
public class UnsafeBank {
    public static void main(String[] args) {
        //账户
        Account account = new Account(100, "基金");

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

        you.start();
        she.start();
    }
}

//账户
class Account {
    int money;//余额
    String name;//卡名

    public Account(int money, String name) {
        this.money = money;
        this.name = name;
    }
}

//银行 模拟取款
class Drawing extends Thread {
    Account account;//账户
    //取了多少
    int drawingMoney;
    //现在手里有多少钱
    int nowMoeny;

    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() + "钱不够");
                return;
            }

            //sleep放大问题的发生性
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            //卡内余额 = 余额 - 你取的钱
            account.money = account.money - drawingMoney;
            //你手里的钱
            nowMoeny = nowMoeny + drawingMoney;

            System.out.println(account.name + "余额为:" + account.money);
            //Thread.currentThread().getName() = this.getName()
            System.out.println(this.getName() + "手里的钱:" + nowMoeny);
        }
    }
}
package com.cyz.demo08;

import java.util.ArrayList;
import java.util.List;

//线程不安全的集合
public class UnsafeList {
    public static void main(String[] args) throws InterruptedException {
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < 10000; i++) {
            new Thread(() -> {
                synchronized (list) {
                    list.add(Thread.currentThread().getName());
                }
            }).start();
        }
        Thread.sleep(3000);
        System.out.println(list.size());
    }
}
package com.cyz.demo08;

import java.util.concurrent.CopyOnWriteArrayList;

public class TestJOC {
public static void main(String[] args) {
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
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());
}

}

死锁

package com.cyz.demo09;

//死锁: 多个线程互相抱着对方需要的资源, 然后形成僵持
public class DeadLock {
public static void main(String[] args) {
Makeup g1 = new Makeup(0,"你");
Makeup g2 = new Makeup(1,"她");

    g1.start();
    g2.start();
}

}

//口红
class Liostick{

}

//镜子
class Mirror{

}

class Makeup extends Thread{

//需要的资源只有一份,用static来保证只有一份
static Liostick liostick = new Liostick();
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();
    }
}

private void makeup() throws InterruptedException {
    if (choice==0){
        synchronized (liostick){//获得口红的锁
            System.out.println(this.girlName+"获得口红的锁");
            Thread.sleep(1000);

            synchronized (mirror){//1s后想获得镜子的锁
                System.out.println(this.girlName+"获得镜子的锁");
            }
        }
    }else{
        synchronized (mirror){//获得镜子的锁
            System.out.println(this.girlName+"获得镜子的锁");
            Thread.sleep(2000);

            synchronized (liostick){//2s后想获得口红的锁
                System.out.println(this.girlName+"获得口红的锁");
            }
        }
    }
}

}

	package com.cyz.demo09;

//死锁: 多个线程互相抱着对方需要的资源, 然后形成僵持
public class DeadLock {
public static void main(String[] args) {
Makeup g1 = new Makeup(0,"你");
Makeup g2 = new Makeup(1,"她");

    g1.start();
    g2.start();
}

}

//口红
class Liostick{

}

//镜子
class Mirror{

}

class Makeup extends Thread{

//需要的资源只有一份,用static来保证只有一份
static Liostick liostick = new Liostick();
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();
    }
}

private void makeup() throws InterruptedException {
    if (choice==0){
        synchronized (liostick){//获得口红的锁
            System.out.println(this.girlName+"获得口红的锁");
            Thread.sleep(1000);
        }
        synchronized (mirror){//1s后想获得镜子的锁
            System.out.println(this.girlName+"获得镜子的锁");
        }
    }else{
        synchronized (mirror){//获得镜子的锁
            System.out.println(this.girlName+"获得镜子的锁");
            Thread.sleep(2000);
        }
        synchronized (liostick){//2s后想获得口红的锁
            System.out.println(this.girlName+"获得口红的锁");
        }
    }
}

}

产生死锁的必要条件

  1. 互斥条件: 一个资源每次只能被一个进程使用

  2. 请求与保持条件: 一个进程因请求资源而阻塞时, 对已获得的资源保持一致

  3. 不剥夺条件: 进程已获得的资源, 在未使用完之前, 不能强行剥夺.

  4. 循环等待条件: 若干进程之间形成一种头尾相接的循环等待资源关系

Lock锁

package com.cyz.demo09;

import java.util.concurrent.locks.ReentrantLock;

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

    new Thread(testLock2).start();
    new Thread(testLock2).start();
    new Thread(testLock2).start();
}

}

class TestLock2 implements Runnable{

int ticketNums = 10;

//定义Lock锁
private final ReentrantLock lock = new ReentrantLock();

@Override
public void run() {
    while (true){

        try {
            lock.lock();//加锁

            if (ticketNums &gt; 0){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(ticketNums--);
            }else{
                break;
            }

        } finally {
            //解锁
            lock.unlock();
        }
    }
}

}

Synchronized 与 Lock 的对比

  1. Lock是显示锁(手动开启和关闭锁) synchronized是隐式锁, 出现作用域自动释放

  2. Lock只有代码块锁, synchronized有代码块锁和方法锁

  3. 使用Lock锁, JVM 将花费较少的时间来角度线程, 性能更好, 并且具有更好的扩展性 (提供更多的子类)

  4. 优先使用顺序

    1. Lock

    2. 同步代码块(已经进入了方法体, 分配了相应资源)

    3. 同步方法(在方法体之外)

生产者和消费者

线程通信

方法名作用
wait() 表示线程一直等待, 直到其他线程通知, 与sleep不同, 会释放锁
wait(long timeout) 指定等待的毫秒数
notify() 唤醒一个处于等待状态的的线程
notifyAll() 唤醒同一个对象上所有调用wait()方法的线程, 优先级别高的优先调度
均是Object类的方法, 都只能在同步方法或者同步代码块中使用, 
否则会抛出异常IllegalMonitorStateException

实现方式

方式一

package com.cyz.demo10;
//管程法
    //生产者, 消费者, 产品, 缓冲区
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 &lt; 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 &lt; 100; i++){
        System.out.println("消费了"+container.pop().id+"只鸡");
    }
}

}

//产品
class Chicken{
int 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 com.cyz.demo10;

//信号灯法
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&lt; 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() {
    for (int i = 0; i&lt; 20; i++){
      tv.watch();
    }
}

}

//产品->节目
class TV{
//演员表演, 观众等待 T
//观众观看, 演员等待 F
String voice;//节目
boolean flag = true;

//表演
public synchronized void play(String voice){

    if (!flag){
        try {
            this.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    System.out.println("演员表演了:"+voice);
    //通知观众看7
    this.notifyAll();//通知唤醒
    this.voice = voice;

    this.flag = !this.flag;
}

//观看
public synchronized void watch(){
    if(flag){
        try {
            this.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    System.out.println("观看了:"+voice);

    //通知演员表演
    this.notifyAll();
    this.flag = !this.flag;
}

}

线程池

好处

  1. 提高响应速度(减少了创建新线程的时间)

  2. 降低资源消耗 (重复利用线程池中线程, 不需要每次创建)

  3. 便于线程管理

    1. corePoolSize: 核心池的大小

    2. maximumPoolSize: 最大线程数

    3. keepAliveTime: 线程没有任务时最多保持多长时间后会停止

实现

  1. execute() 执行Runnable

  2. shutdown() 关闭连接池

package com.cyz.demo10;
?
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
?
public class TestPool {
?
   public static void main(String[] args) {
       //1. 创建服务, 创建线程池
       //newFixedThreadPool 参数为线程池大小
       ExecutorService service = Executors.newFixedThreadPool(10);
?
       service.execute(new MyThread());
       service.execute(new MyThread());
       service.execute(new MyThread());
       service.execute(new MyThread());
?
       //2. 关闭连接
       service.shutdown();
?
  }
?
}
?
class MyThread implements Runnable {
?
   @Override
   public void run() {
       System.out.println(Thread.currentThread().getName());
  }
}
?

原文:https://www.cnblogs.com/liang-chen-fly/p/14490872.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!