其他分享
首页 > 其他分享> > 线程学习(持续更新)

线程学习(持续更新)

作者:互联网

 

线程学习

在这里插入图片描述

线程简介

多任务:看起来多个任务同时做 但本质上我们的大脑在同一时间只做了一件事情

多线程 :增加车道 不担心道路阻塞

普通方法调用和多线程

在这里插入图片描述

 

程序 进程 线程

在操作系统中运行的程序就是进程

一个进程可以有多个线程 如视频中同时听声音 看画面..

自我理解: 程序运行->就叫进程 一个进程里有多个线程 线程是执行人物的 进程只是一个壳子 用来装载那些线程 并且系统是以进程这个壳子为单位来分配资源

在这里插入图片描述

 

核心概念

一. 创建线程 实现线程

1. 继承Thread类

子类继承Thread类 具备多线程能力

启动线程 :子类对象.start();

不建议使用 避免oop单继承局限性

自定义线程继承Thread类

重写run()方法 编写线程执行体

创建线程对象 调用start()方法启动线程

package kuang;

public class ThreadReview extends Thread{

//线程入口点
//Thread实现了Runnable的run 自己写的类要去重写这个run()
@Override
public void run() {
//线程体
for(int i=0;i<100;i++)
{
//try {
//Thread.sleep(1);
/} catch (InterruptedException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
//}
System.out.println("子线程--"+i);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ThreadReview t = new ThreadReview(); //创建线程对象
t.start(); //子线程执行run()方法 主线程和子线程同时进行 主线程和子线程都没停下 在同一时间只能执行一条线程(因为我们的电脑是单核的)
for(int i=0;i<100;i++)
{
System.out.println("我在学习多线程--"+i);
}
}

}

运行效果

我在学习多线程--0
我在学习多线程--1
子线程--0
我在学习多线程--2
子线程--1
我在学习多线程--3
子线程--2
我在学习多线程--4
子线程--3
我在学习多线程--5
子线程--4
我在学习多线程--6
子线程--5
我在学习多线程--7
子线程--6
我在学习多线程--8
子线程--7
我在学习多线程--9
子线程--8
我在学习多线程--10
子线程--9
我在学习多线程--11
子线程--10
我在学习多线程--12
子线程--11
我在学习多线程--13
子线程--12
我在学习多线程--14
子线程--13
我在学习多线程--15
子线程--14
我在学习多线程--16
子线程--15
我在学习多线程--17
子线程--16
我在学习多线程--18
子线程--17
我在学习多线程--19
子线程--18
我在学习多线程--20
子线程--19
子线程--20

 

 

下载网图 不会导入jar包 学完这一章再补上

package com.kuang.thread;

import org.apache.commons.io.FileUtils;

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

//练习Thread,实现一个多线程同步下载图片
public class TestThread02 extends Thread {
   private String url; //网络我图片地址
   private String FileName;   //保存的文件名

   public TestThread02(String url, String FileName) {
       this.url = url;
       this.FileName = FileName;
  }

   //下载图片线程的执行体
   @Override
   public void run() {
       super.run();
       WebDownloader webDownloader = new WebDownloader();
       try {
           webDownloader.downloader(url, FileName);
           System.out.println("下载的文件名:" + FileName);
      } catch (IOException e) {
           e.printStackTrace();
      }
  }

   public static void main(String[] args) {
       TestThread02 testThread01 = new TestThread02("https://www.baidu.com/img/baidu_jgylogo3.gif", "copy1.png");
       TestThread02 testThread02 = new TestThread02("https://www.baidu.com/img/baidu_resultlogo@2.png", "copy2.png");
       TestThread02 testThread03 = new TestThread02("https://www.baidu.com/img/bd_logo1.png", "copy3.png");

       //理想状态是先下载t1,最后t2,最后t3
       //实质上是几乎同时执行,不一定是这个顺序
       testThread01.start();
       testThread02.start();
       testThread03.start();
  }
}

//下载器
class WebDownloader {
   //下载方法
   public void downloader(String url, String filename) throws IOException {

       try {
           FileUtils.copyURLToFile(new URL(url), new File(filename));
      } catch (IOException e) {
           e.printStackTrace();
           System.out.println("IO异常");
      }
  }
}


//运行结果
//下载的文件名:copy3.png
//下载的文件名:copy2.png
//下载的文件名:copy1.png

 

 

2.实现Runnable接口

实现接口Runnable 具有多线程能力

启动线程 传入目标对象 ; Thread类对象.start();

推荐使用 :避免单继承局限性

灵活方便 方便同一个对象被多个线程使用

定义MyRunnable类实现Runnable接口

实现run()方法 编写线程执行体

创建线程对象 调用start()方法启动线程

package kuang;

public class MyRunnable implements Runnable{

public void run() {
for(int i=0;i<50;i++) {
System.out.println("子线程---"+i);
}
}

public static void main(String args[]) {
Runnable r = new MyRunnable();//创建Runnable接口的实现类对象
Thread t =new Thread(r);//创建线程对象 通过线程对象开启线程 ---代理
t.start();
// new Thread(new MyRunnable()).start();
for(int i=0;i<100;i++) {
System.out.println("main线程--"+i);
}
}
}

案例 买火车票

多个线程共享同一资源可能会发生冲突

package kuang;

public class MyTask implements Runnable{

private static int ticketNum =  0 ;//好像不写static也行 因为那些线程用到都是同一个对象MyTask

@Override
public void run() {
// TODO Auto-generated method stub
while(true) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(ticketNum>10) {
break;
}
System.out.println(Thread.currentThread().getName()+"买到了第"+(ticketNum++)+"票");
}
}

public static void main(String args[]) {
MyTask mt = new MyTask();//一个接口的实现对象可以交给多个线程类对象使用 方便 如果用自己写Thread类的方法的话 需要写三个 但还都是一样的方法
Thread t1 = new Thread(mt,"小明");//第二个参数是线程的名字
Thread t2 = new Thread(mt,"老师");
Thread t3 = new Thread(mt,"黄牛");
t1.start();
t2.start();
t3.start();
}

}

案例 龟兔赛跑

package kuang;

public class Race1 implements Runnable{

private static String winner = null;

@Override
public void run() {
// TODO Auto-generated method stub

for(int i=0;i<=100;i++)
{
if(Thread.currentThread().getName()=="兔子") {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
boolean flag = GameOver(i);
if(flag) break;/**跳出循环 结束循环 线程体的任务结束了 故线程也就结束了 结束了比赛**/
           //先判断 后输出 有可能这步走不出来(比赛已经结束)
System.out.println(Thread.currentThread().getName()+"走了第"+i+"步");
}

}

private boolean GameOver(int step) {
// TODO Auto-generated method stub
if(winner!=null) return true;//为败者准备的
if(step>=100) {
winner  =  Thread.currentThread().getName();
System.out.println(winner+"走了第100步"+" "+"winner is"+winner);
return true;
}
return false;
}

public static void main(String args[]) {
Race1 r = new Race1();
new Thread(r,"兔子").start();
new Thread(r,"乌龟").start();
}
}

 

 

 

Callable接口 了解即可

package com.kuang.thread;

import java.util.concurrent.*;

/**
*Callable<Boolean>表示接口需要实现的Call()方法返回值类型
*/
public class TestCallable01 implements Callable<Boolean> {

   private String url; //网络我图片地址
   private String FileName;   //保存的文件名

   public TestCallable01(String url, String FileName){
       this.url = url;
       this.FileName = FileName;
  }

   //下载图片线程的执行体

   public Boolean call() throws Exception {
       WebDownloader webDownloader = new WebDownloader();
       try {
           webDownloader.downloader(url,FileName);
           System.out.println("下载的文件名:" + FileName);
      } catch (Exception e) {
           e.printStackTrace();
      }
       return true;
  }

   public static void main(String[] args) throws ExecutionException, InterruptedException {
       TestCallable01 t1 = new TestCallable01("https://www.baidu.com/img/baidu_jgylogo3.gif","copy1.png");
       TestCallable01 t2 = new TestCallable01("https://www.baidu.com/img/baidu_resultlogo@2.png","copy2.png");
       TestCallable01 t3 = new TestCallable01("https://www.baidu.com/img/bd_logo1.png","copy3.png");

       //1:创建执行服务:
       //param: 有创建三个线程
       ExecutorService ser = Executors.newFixedThreadPool(3);
       //2:提交执行
       Future<Boolean> r1 = ser.submit(t1);
       Future<Boolean> r2 = ser.submit(t2);
       Future<Boolean> r3 = ser.submit(t3);
       //3:获取结果
       boolean rs1 = r1.get();
       boolean rs2 = r2.get();
       boolean rs3 = r3.get();

       System.out.println(rs1);
       System.out.println(rs2);
       System.out.println(rs3);
       //4:关闭服务
       ser.shutdown();
  }
}


//
下载的文件名:copy1.png
下载的文件名:copy3.png
下载的文件名:copy2.png
true
true
true

 

静态代理

静态代理:线程的底部实现原理*

真实对象和代理对象都要实现同一个接口

代理对象要代理真实角色[真实角色以参数传进去]

好处:代理对象可以做很多真实对象做不了的事情 真实对象可以专注做自己的事情

package kuang;

/**静态代理模式**/
//静态代理模式:
//代理对象与真实对象都要实现同一个接口
//代理对象要代理真是角色[参数传进去]
/**好处:代理对象可以做很多真实对象做不了的事情 真实对象可以专注做自己的事情**/
//注意同一个包下的类不能重名
public class StaticProxyTest {
public static void main(String args[]) {
//Youx you = new Youx();
//WeddingCompanyx wdx = new WeddingCompanyx(you);
//wdx.HappyMarry();
       new WeddingCompany(new Youx()).HappyMarry();
}

}

//接口 一个特殊的类 类名后面不带括号!
//静态代理模式:
//代理对象与真实对象都要实现同一个接口
//代理对象要代理真是角色[参数传进去]
//每个编译单元(文件)都只能有一个public类。这表示,每个编译单元都有单一的公共接口,用public类来表现的
interface Marryx{
void HappyMarry();
}

/**真实对象 你去结婚**/
class Youx implements Marryx{
public void HappyMarry() {
System.out.println("shc今天结婚了 超开心!");
}
}

/**代理角色 帮助你结婚**/
class WeddingCompanyx implements Marryx{
private Marryx target;
//You实现了Marru接口 即可交由接口变量对象管理 并且接口对象只能带调用接口中有的函数
//实例变量如果不初始化会自动赋默认值 所以不初始化也不报错

public WeddingCompanyx(Marryx target) {
this.target = target;
}

public void HappyMarry() {
before();//代理对象多做的事情
this.target.HappyMarry();///通过代理角色Company来调用[真实对象]You的结婚方法
after();//代理对象多做的事情
}

private void after() {
// TODO Auto-generated method stub
System.out.println("收尾款");
}

private void before() {
// TODO Auto-generated method stub
System.out.println("布置现场");
}

}

new Thread(new Runnable(){public void run(){..}}).start();
new Thread(()->{System.out.println();}).start();
new WeddingCompany(new You()).HappyMarry();

Thread -Runnable 代理对象 实现了Runnable接口
new Runnbale() -- You 真实对象 实现了Runnabe接口     
(HappMarry和start/run 是覆盖的接口的方法)
    
  静态代理:线程的底部实现原理
    

Lambda表达式

在这里插入图片描述

在这里插入图片描述

 

线程状态

五大状态

 

在这里插入图片描述

 

 

线程方法

    setPriority(int new Priority) //更改线程优先级
    static void sleep(long mills) //在指定的毫秒数内 让当前正在执行的线程体休眠
    void join() //等待该线程终止
    static void yield //暂停正在执行的线程对象 并执行其他线程
	void interrupt() //中断线程 别用这个方法
    boolean isAlive() //判断线程是否处于活动状态

停止线程

1615011500678

样例

//模板
public TestStop implements Runnable{
    //1.设置一个标识位
    private boolean flag = true;
    //2.线程体使用该标识
    public void run(){
        while(flag){
            ...
        }
    }
    //3.对外提供方法改变标识
    public void stop(){
        this.flag = flase;
    }
    
    public static void main(String args[]){
       Teststop teststop = new TestStop();//这个对象既可用TestStop引用管理,也可以用Runnable管理
       new Thread(teststop).start();//线程进入就绪状态
       teststop.stop();//利用自己imlements Runnable的时候写的stop方法来结束线程 而不是调用Thread类本身的stop方法
       
    }
    
}

案例 不看也罢hh

package kuang03;

/**
 * 测试stop
 * 1.建议线程正常停止
 * 2.建议使用标志变量
 * 3.不要使用stop或destroy等过时或者JDK不建议使用的的方法
 * @author de'l'l
 *
 */
//接口类写法
public class TestStop implements Runnable{
	/**设置一个标识位**/
	private boolean flag = true;
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		int i=0; //如果放在while里面就会一直定义
		while(flag) {
			System.out.println("run...Thread"+i++);
		}
	}
	
	//runnable接口:函数式接口 只有一个abstract的run方法 无stop方法
	/**为外部提供一个方法改变标识位**/
	//设置一个公开的方法转换标识位 结束线程
	public void stop() {
		this.flag = false;
	}
	
	public static void main(String args[])
	{
		TestStop teststop = new TestStop();
		new Thread(teststop).start();//teststop implements 了Runnable接口 那么他就可以被当作Runnbale类型来使用 Thread需要一个Runnable 所以可以传进去	
		for(int i=0;i<1000;i++) {
			System.out.println("main--"+i);
			if(i==900) {
//				调用stop方法 使线程停止
				teststop.stop();//teststop的flag变成flase run方法里的while终止 TestStop提供的run()方法结束 线程结束
				System.out.println("thread停止了");
			}
		}
	}
	

}





//继承自Thread类写法
//public class TestStop extends Thread{
//	
//	private boolean flag = true;
//	
//	@Override
//	public void run() {
//		int i=1;
//		while(flag) {
//			System.out.println("run...Thread"+i++);
//		}
//	}
//	
//	public void stopp() {
//		this.flag = false;
//	}
//	
//	public static void main(String[] args) {
//		// TODO Auto-generated method stub
//		Thread t = new TestStop();
//		t.start();
//		for(int i=0;i<2000;i++) {
//			System.out.println("main线程--"+i);
//			if(i==900) {
//				t.stop();
//				System.out.println("t线程停止了");
//			}
//		}
//	}
//
//}

线程休眠_sleep

在这里插入图片描述

模拟网络延时 扩大问题发生性

package kuang;
//发现问题:多个线程操作统一资源 的情况下 数据紊乱 线程不安全
public class TestThread3 implements Runnable{
	
	private int ticketNum = 10;
	public void run() {
		while(true)
		{
			if(ticketNum<=0) break;
			try {
				//模拟延时
				Thread.sleep(100);
				System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNum--+"张票");
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}		
		}
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TestThread3 task = new TestThread3();
		new Thread(task,"小明").start();
		new Thread(task,"老师").start();
		new Thread(task,"黄牛党").start();	
	}
}

模拟倒计时

public class TestSleep{
    private static int num = 10;
    public static void tenDown throws InterruptedException(){
        while(true){
            Thread.sleep(1000);
            System.out.println(num--);
            if(num<=0) break;
        }
    }
    public void static void main(String args[]){
        try{
            tenDown();
        }catch(...){}
    }
}

获取当前系统时间!!!很重要

public class TestSleep{
    public static void main(String args[]){
        //获取当前系统时间
        Date startTime = new Date(System.currentTimeMills());//mill n.工厂
        while(true){
            try{
                Thread.sleep(1000);
                //					   格式化工厂	参数格式(小时 分钟 毫秒).format(时间); 
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
                startTime = new Date(System.currentTimeMills());
            }
        }
    }
}

线程礼让

package kuang03;

public class YieldTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MyYield y = new MyYield();
		new Thread(y,"t1").start();
		new Thread(y,"t2").start();
	}

}

class MyYield implements Runnable{

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println(Thread.currentThread().getName()+"开始执行");
		Thread.yield();//礼让
		System.out.println(Thread.currentThread().getName()+"结束执行");
	}
	
}

join

尽量少用

public class TestJoin implements Runnable{

	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		Thread t = new Thread(new TestJoin());
		t.start();
		for(int i=0;i<10;i++) {
			if(i==8) {
				t.join();
			}
			System.out.println("main"+i);
		}
		
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i=0;i<100;i++) {
			System.out.println("VIP来了"+i);
		}
	}

}

运行结果
 main0
main1
main2
VIP来了0
main3
main4
main5
VIP来了1
VIP来了2
VIP来了3
VIP来了4
VIP来了5
main6
VIP来了6
VIP来了7
main7
VIP来了8
VIP来了9
VIP来了10
VIP来了11
VIP来了12
VIP来了13
    ...
VIP来了97
VIP来了98
VIP来了99
main8
main9
   

线程状态观测

img

package kuang03;

import java.lang.Thread.State;

//观察测试线程状态
public class TestState {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Thread t = new Thread(()->{
			for(int i=0;i<6;i++) {
				try {
					Thread.sleep(1000);
					System.out.println(i);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			System.out.println("\\\\\\\\");
		});
		
		/**获取线程状态**/
		Thread.State state = t.getState();
		System.out.println(state);//new
		
		//启动后
		t.start();
		state = t.getState();//runnable
		System.out.println(state);
		
		//运行时
		while(state!=Thread.State.TERMINATED) {//只要线程不终止 就一直输出状态
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			state=t.getState();//waited 因为线程中有sleep
			System.out.println(state);
		}
		
		t.start();//线程一旦死亡之后的线程不能在开启
	}

}


 

NEW 			//Thread t = new Thread(()->{}); 刚被new出来
RUNNABLE 		//t。start()
TIMED_WAITING	//线程中有sleep
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
0
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
1
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
2
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
3
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
RUNNABLE			//sleep的间断--在执行线程体 
    //sleep为阻塞事件 阻塞事件结束后 重新进入就绪状态 等待cpu调度执行 变成运行状态
4
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
5
\\\\
TERMINATED
Exception in thread "main" java.lang.IllegalThreadStateException
	at java.base/java.lang.Thread.start(Thread.java:792)
	at kuang03.TestState.main(TestState.java:44)

在这里插入图片描述

 

 

 

 

 

线程优先级

先设置优先级 后启动线程

package kuang03;

//测试优先级
public class TestPriority {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(Thread.currentThread().getName()+"-----"+Thread.currentThread().getPriority());
		
		Thread t1 = new Thread(new MyPriority());//代理:把线程体丢进去 让线程替他跑
		Thread t2 = new Thread(new MyPriority());
		Thread t3 = new Thread(new MyPriority());
		Thread t4 = new Thread(new MyPriority());
		Thread t5 = new Thread(new MyPriority());
		Thread t6 = new Thread(new MyPriority());
		
		//先设置优先级 后启动
		t1.start();
		
		t2.setPriority(2);
		t2.start();
		
		t3.setPriority(9);
		t3.start();
		
		t4.setPriority(Thread.MAX_PRIORITY);//10 注意是!!Thread.!!别忘了加类名
		t4.start();
		//因为/**
//	     * The maximum priority that a thread can have.
//	     */
//	    public static final int MAX_PRIORITY = 10;
		
		t5.setPriority(11);
		t5.start();
		
		t6.setPriority(-1);
		t6.start();
	}

}

class MyPriority implements Runnable{
	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println(Thread.currentThread().getName()+"---"+Thread.currentThread().getPriority());
	}
}

我的不知道为啥结果总是性能倒置
main====>5
3====>5
1====>5
2====>1
4====>10

守护线程

人生不过三万天

开心点儿 朋友

package kuang03;

public class TestDaemon {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		God god = new God();
		You you = new You();
		
		Thread t = new Thread(god); //正常的线程都是用户线程
		t.setDaemon(true);	//默认为false表示是用户线程 正常的线程都是用户线程
		t.start();
		
		new Thread(you).start();//你 用户线程
	}

}


//上帝
class God implements Runnable{
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true) {
			System.out.println("上帝保佑着你");
		}
	}
}


    

 

 

线程同步

2.取钱

package kuang03;

//人去银行取钱
public class UnSafeBank {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Account account = new Account("结婚基金",101);
		Drawing you = new Drawing("you",account,50);//对同一个account进行操作
		Drawing she = new Drawing("she",account,100);
		you.start();
		she.start();
	}

}

//账户
class Account{
	//账户名
	//余额
	String name ;
	private int money;
	
	public Account(String name,int money) {
		this.name = name;
		this.money = money;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getMoney() {
		return money;
	}

	public void setMoney(int money) {
		this.money = money;
	}
	
	
}

//模拟取款
class Drawing extends Thread{
//	private String name;收钱人的名字 不需要!!! 我们把线程的名字用人名命名即可
	private int nowMoney;//手里的钱
	private int drawingMoney;//要取的钱
	private Account account;//从哪个账户里取
	
    //Thread类中没有三个参数的构造函数 所以要自己写
	public Drawing(String name,Account account,int drawingMoney) 	{	
        //调用父类的构造函数 new Thread("名字"); 线程名字
		super(name);//!!!!!!! extends Thread 为线程赋名字
		this.account = account;
		this.drawingMoney = drawingMoney;
	}
	
	@Override
	public void run() {
		if(account.getMoney()<this.drawingMoney) {
			//这里的this.getName()<--->Thread.currentThread().getName() 
			//因为Drawing类继承于Thread类 自然继承了所有public方法
			//而在子类中getName方法有没有重写 所以this.(即该类对象.)引用的就是父类Thread的getName()
			System.out.println(account.getName()+"账户钱不够了"+this.getName()+"没取出来");
			return ;//记得return啊
		}
		
		/**Thread.sleep()放大问题的发生性**/
		//出错原因:"各自把数据拷贝到各自的内存"
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		account.setMoney(account.getMoney() - drawingMoney);
		nowMoney = drawingMoney;
		
		System.out.println(account.getName()+"余额为"+account.getMoney());
		
		System.out.println(this.getName()+"手里的钱为:"+nowMoney);
	}
}
//在new Thread时可以给线程名字
//而不是在写Runnable接口的时候给线程起名字
//new Thread(接口,"名字");
//接口与"名字"不用自己写参数接收 会直接调用父类Thread的构造函数

结婚基金余额为-49
结婚基金余额为-49
she手里的钱为:100
you手里的钱为:50

3.不安全集合

package kuang03;

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++) {
			//每次循环开启一个线程 往同一list里加东西
			new Thread(()->{
				list.add(Thread.currentThread().getName());
			}).start();
			//结果小于10000原因?:两个线程在同一时间对同一个List的同一个位置进行操作 
			//两个东西加到同一个位置 所以后加入的会覆盖先覆盖的 所以小于10000
		}
		Thread.sleep(100);
		System.out.println(list.size());
	}

}

9994

 

 

 

同步方法

同步块

买票

package kuang03;

//不安全的买票 有负数
public class UnSafeBuyTicket {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		BuyTicket by = new BuyTicket();
		new Thread(by,"帅气的我").start();
		new Thread(by,"可恶的你").start();
		new Thread(by,"黄牛们").start();
		
		//WRONG!!! 应该对同一种票数进行操作 而我们的票数定义的又不是static 所以必须使用同一个BUyTicket对象!!
		//线程自然应当是每次new一个新的(因为是不同人买) 而实现了接口的类的对像应该是同一个(要执行的线程体)
		//如果票数定义为static的话 则可以是使用不同对象
//		new Thread(new BuyTicket(),"帅气的我").start();
//		new Thread(new BuyTicket(),"臭臭的你").start();
//		new Thread(new BuyTicket(),"黄牛们").start();
	}

}

class BuyTicket implements Runnable{
	//票
	private static int ticketNum = 10;
	private boolean flag = true;
	
	//买票
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(flag) {
			//模拟买票延时
			buy();
		}
	}
	
	
	
	//如何买票
	//synchronized 同步方法 锁的是this
	public synchronized void buy() {
		if(ticketNum<=0) {
			flag = false;
			return ;//别忘了return!!!! 发现没票之后立刻return 不然又要多买
		}
		
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		System.out.println(Thread.currentThread().getName()+"买到了第"+(ticketNum--)+"张票");
	}
}

 

取钱

synchronized块可以锁任何对象-----synchronized(对象){ ...} 我们应该锁增删改查的对象

package kuang03;

//人去银行取钱
public class UnSafeBank {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Account account = new Account("结婚基金",1000);
		Drawing you = new Drawing("you",account,50);//对同一个account进行操作
		Drawing she = new Drawing("she",account,100);
		you.start();
		she.start();
	}

}

class Account{
	//账户名
	//余额
	String name ;
	private int money;
	
	public Account(String name,int money) {
		this.name = name;
		this.money = money;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getMoney() {
		return money;
	}

	public void setMoney(int money) {
		this.money = money;
	}
	
	
}

//模拟取款
class Drawing extends Thread{
//	private String name;收钱人的名字 不需要!!! 我们把线程的名字用人名命名即可
	private int nowMoney;//手里的钱
	private int drawingMoney;//要取的钱
	private Account account;//从哪个账户里取
	
	public Drawing(String name,Account account,int drawingMoney) {
		super(name);//!!!!!!! extends Thread 为线程赋名字
		this.account = account;
		this.drawingMoney = drawingMoney;
	}
	
	
	
	@Override
	//这里对方法run()上锁没有用 两个对像 You 和She 各自开启一条线程 对同一个对象account进行修改访问 应该对account上锁
	/**synchronized 默认锁的是this 是所在的这个类的对象本身**/
	public  void  run() {
		
		/**synchronized块可以锁任何对象**/
		/**我们应该锁增删改查的对象**/
		synchronized(account) {
			if(account.getMoney()<this.drawingMoney) {
				//这里的this.getName()<--->Thread.currentThread().getName() 
				//因为Drawing类继承于Thread类 自然继承了所有public方法
				//而在子类中getName方法有没有重写 所以this.(即该类对象.)引用的就是父类Thread的getName()
				System.out.println(account.getName()+"账户钱不够了"+this.getName()+"没取出来");
				return ;//记得return啊
			}
			
			/**Thread.sleep()放大问题的发生性**/
			//出错原因:"各自把数据拷贝到各自的内存"
			//停了1秒 you和she都走到了这里 两人会接尽同时对同一对象进行操作
			//自我理解:停了1s you只对account.getMoney()和drawingMoney进行了判断操作 并没有改变余额(account的money) 所以she判断时用的也是这个数
			//而计算时 you:101-50=51; she:51-100=-49;
			//所以出错了
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			account.setMoney(account.getMoney() - drawingMoney);
			nowMoney = drawingMoney;
			
			System.out.println(account.getName()+"余额为"+account.getMoney());
			
			System.out.println(this.getName()+"手里的钱为:"+nowMoney);
		}
	}
}



结婚基金余额为950
you手里的钱为:50
结婚基金余额为850
she手里的钱为:100

 

 

List

package kuang03;

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++) {
			//每次循环开启一个线程 往同一list里加东西
			new Thread(()->{
				synchronized(list) {
					list.add(Thread.currentThread().getName());
				}
			}).start();
			//结果小于10000原因?:两个线程在同一时间对同一个List的同一个位置进行操作 
			//两个东西加到同一个位置 所以后加入的会覆盖先覆盖的 所以小于10000
		}
		Thread.sleep(100);
		System.out.println(list.size());
	}

}


10000

 

JUC CopyOnWriteArrayList
package kuang03;

import java.util.concurrent.CopyOnWriteArrayList;
//JUC安全类型的集合
public class TestJUC {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
		for(int i=0;i<10000;i++)
		{
			new Thread(()->{
				list.add(Thread.currentThread().getName());
				}
			).start();
		}
		
		System.out.println(list.size());
	}

}
10000

 

就相当于我们上面改进的集合·

List<String> list = new ArrayList<String>();
for(int i=0;i<1000;i++)
{
    new Thread(()->{
        synchnorized(list){
            list.add(list.add(Thread.currentThread.getName());)
		}
    }).start();
}

 

死锁

package kuang03;

//死锁:多个线程互相抱着对方需要的资源 然后形成僵持
public class DeadLock {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new MakeUp("灰姑娘",0).start();
		new MakeUp("白雪公主",1).start();
	}

}

class LipStick{
	
}

class Mirror{
	
}

class MakeUp extends Thread{
//	private String name ;//化妆的人
	private int choice;//选择
	//猜测:如果这里写的是覆盖Runnable接口写法的话就不用static 因为丢进两个线程的是同一个对象
	private static LipStick lipstick = new LipStick();
	private static Mirror mirror = new Mirror();
	
	public MakeUp(String name,int choice){
//		this.name = name;
		super(name);//化妆的人作为线程的名字
		this.choice = choice;
	}
	
	public void run() {
		//化妆
		try {
			makeup();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	//化妆 互相持有对方的锁 就是需要拿到对方的资源
	private void makeup() throws InterruptedException {
		// TODO Auto-generated method stub
		if(choice==0) {
			synchronized(lipstick) {//获得口红的锁
				System.out.println(this.getName()+"获得空红的锁");
				Thread.sleep(2000);
//				synchronized(mirror) {//一秒钟后获得镜子
//					System.out.println(this.getName()+"获得镜子的锁");
//				}
				//灰姑娘抱着口红的锁不放 还要去拿镜子的锁
				//但是想要拿到镜子的锁就必须先让白雪公主方下镜子的锁 但如果想让她放下镜子的锁 他就必须先拿到口红的锁 但口红锁现在又放不掉 所以死循环
				//解决方法 把那这段synchronized代码放在这个synchronized外面 这样就可以顺利执行完第一段synchronized代码块 释放锁
			}
			synchronized(mirror) {//一秒钟后获得镜子
				System.out.println(this.getName()+"获得镜子的锁");
			}
		}
		else
		{
			synchronized(mirror) {//获得镜子的锁
				System.out.println(this.getName()+"获得镜子的锁");
				Thread.sleep(2000);
				synchronized(lipstick) {//一秒钟获得口红的锁
					System.out.println(this.getName()+"获得口红的锁");
				}
				//白雪公主抱着镜子的锁不放 还要去拿口红的锁
			}
		}
	}
}

 

 

Lock

买票例子

package kuang03;

import java.util.concurrent.locks.ReentrantLock;

public class TestLock {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		BuyTickets by = new BuyTickets();
		new Thread(by).start();
		new Thread(by).start();
		new Thread(by).start();
	}

}

class BuyTickets implements Runnable{
	private static int num = 10;
	
	/**定义Lock锁**/
	private final ReentrantLock lock = new ReentrantLock();
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true) {
			try {
				lock.lock();/**加锁**/
				if(num<=0) break;
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(num--);
			}finally {
				lock.unlock();/**显式上锁之后一定显式释放锁*/
			}
			
		}
	}
}


//能明显感觉出是一个一个出来的
10
9
8
7
6
5
4
3
2
1

Lock锁模板

class A{
    private final ReentrantLock lock = new ReentrantLock();
    public void m(){
        lock.lock();//显式上锁
        try{
            //一定会是线程安全的代码
           //保证是线程安全的代码
        }
        finally{
            lock.unlock();//释放锁
            //如果同步代码有异常 要将unlock()写入finally语句块
        }
    }
}

 

synchronized 与 Lock的对比

线程通信

生产者消费者模式

 

 

 

容器法
package kuang03;

//生产者 消费者 产品 缓冲区
//生产者只管生产
//消费者只管消费
//通过缓冲区交互(何时消费何时生产)
//方法.wait() 表示线程一直等待 直到其他线程通知 与sleep不同 会释放锁
//方法.notifyAll() 唤醒同一个对象上所有调用wait()的方法,优先级高的线程优先调度
public class TestPC {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		SynContainer container = new SynContainer();
		new Producer(container).start();
		new Consumer(container).start();
	}

}

//生产者
class Producer extends Thread{
	SynContainer container;
	
	public Producer(SynContainer container) {
		this.container = container;
	}
	
	//生产
	@Override
	public void run() {
		for(int i=0;i<100;i++) {
			 System.out.println("生产了"+i+"只鸡");
		    container.push(new Chicken(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;
	public Chicken(int id) {
		this.id = id;
	}
}

class SynContainer{
	//容器类型,大小
	Chicken []chickens = new Chicken[10];
	//容器计数器
	private static int count = 0;
	
	//synchronized:同一时间只有一个线程能对这同一个container对象进行操作 改变它的count
	//生产者投入产品
	public synchronized void push(Chicken chicken) {
		//如果容器满了,就需要等待消费者消费
		if(count==chickens.length) 
		{
			//生产者等待
			try {
				this.wait();
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		//如果没有满 需要放入产品
		chickens[count++]=chicken;//count保持指向下一位放鸡的地方
		
		//可以通知消费者消费了
		this.notifyAll();//通知正在wait()的方法不用等待了
		
	}
	
	//消费者消费产品
	public synchronized Chicken pop() {
		//判断能否消费
		if(count==0) {
			//消费者等待生产者生产
			try {
				this.wait();
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		//如果可以消费
		Chicken chicken = chickens[--count];
		
		//吃完了 通知生产者生产
		this.notifyAll();
		
		//返回消费的鸡
		return chicken;
		
	}
	
}
生产了0只鸡
生产了1只鸡
消费了--->0只鸡
消费了--->1只鸡
生产了2只鸡
生产了3只鸡
消费了--->2只鸡
消费了--->3只鸡
生产了4只鸡
生产了5只鸡
消费了--->4只鸡
生产了6只鸡
消费了--->5只鸡
消费了--->6只鸡
生产了7只鸡
生产了8只鸡
消费了--->7只鸡
生产了9只鸡
消费了--->8只鸡
生产了10只鸡
消费了--->9只鸡
消费了--->10只鸡
生产了11只鸡
生产了12只鸡
消费了--->11只鸡
生产了13只鸡
消费了--->12只鸡
生产了14只鸡
消费了--->13只鸡
生产了15只鸡
消费了--->14只鸡
生产了16只鸡
消费了--->15只鸡
消费了--->16只鸡
生产了17只鸡
生产了18只鸡
生产了19只鸡
消费了--->17只鸡
消费了--->19只鸡
生产了20只鸡
消费了--->18只鸡
消费了--->20只鸡
生产了21只鸡
生产了22只鸡
生产了23只鸡
消费了--->21只鸡
生产了24只鸡
消费了--->23只鸡
消费了--->24只鸡
生产了25只鸡
生产了26只鸡
消费了--->22只鸡
消费了--->26只鸡
消费了--->25只鸡
生产了27只鸡
生产了28只鸡
生产了29只鸡
消费了--->28只鸡
生产了30只鸡
消费了--->29只鸡
消费了--->30只鸡
消费了--->27只鸡
生产了31只鸡
生产了32只鸡
生产了33只鸡
生产了34只鸡
消费了--->31只鸡
生产了35只鸡
消费了--->34只鸡
消费了--->35只鸡
生产了36只鸡
生产了37只鸡
生产了38只鸡
生产了39只鸡
生产了40只鸡
消费了--->33只鸡
生产了41只鸡
消费了--->40只鸡
生产了42只鸡
消费了--->41只鸡
消费了--->42只鸡
消费了--->39只鸡
生产了43只鸡
生产了44只鸡
消费了--->38只鸡
生产了45只鸡
消费了--->44只鸡
生产了46只鸡
生产了47只鸡
生产了48只鸡
生产了49只鸡
生产了50只鸡
生产了51只鸡
消费了--->45只鸡
消费了--->51只鸡
生产了52只鸡
消费了--->50只鸡
生产了53只鸡
生产了54只鸡
消费了--->52只鸡
生产了55只鸡
生产了56只鸡
消费了--->54只鸡
消费了--->55只鸡
消费了--->53只鸡
消费了--->49只鸡
消费了--->56只鸡
消费了--->48只鸡
消费了--->47只鸡
生产了57只鸡
消费了--->46只鸡
生产了58只鸡
生产了59只鸡
生产了60只鸡
生产了61只鸡
生产了62只鸡
生产了63只鸡
生产了64只鸡
消费了--->57只鸡
消费了--->63只鸡
消费了--->62只鸡
消费了--->64只鸡
消费了--->61只鸡
消费了--->60只鸡
生产了65只鸡
消费了--->59只鸡
生产了66只鸡
消费了--->65只鸡
生产了67只鸡
消费了--->66只鸡
生产了68只鸡
消费了--->67只鸡
生产了69只鸡
消费了--->68只鸡
生产了70只鸡
消费了--->69只鸡
生产了71只鸡
消费了--->70只鸡
生产了72只鸡
消费了--->71只鸡
生产了73只鸡
消费了--->72只鸡
生产了74只鸡
消费了--->73只鸡
生产了75只鸡
消费了--->74只鸡
生产了76只鸡
消费了--->75只鸡
消费了--->76只鸡
生产了77只鸡
消费了--->58只鸡
消费了--->77只鸡
消费了--->43只鸡
生产了78只鸡
消费了--->37只鸡
生产了79只鸡
消费了--->78只鸡
消费了--->79只鸡
消费了--->36只鸡
消费了--->32只鸡
生产了80只鸡
生产了81只鸡
消费了--->80只鸡
生产了82只鸡
消费了--->81只鸡
消费了--->82只鸡
生产了83只鸡
生产了84只鸡
消费了--->83只鸡
生产了85只鸡
消费了--->84只鸡
生产了86只鸡
消费了--->85只鸡
生产了87只鸡
消费了--->86只鸡
生产了88只鸡
消费了--->87只鸡
生产了89只鸡
消费了--->88只鸡
生产了90只鸡
消费了--->89只鸡
生产了91只鸡
消费了--->90只鸡
生产了92只鸡
消费了--->91只鸡
生产了93只鸡
消费了--->92只鸡
生产了94只鸡
消费了--->93只鸡
生产了95只鸡
消费了--->94只鸡
生产了96只鸡
消费了--->95只鸡
生产了97只鸡
消费了--->96只鸡
生产了98只鸡
消费了--->97只鸡
生产了99只鸡
消费了--->98只鸡
消费了--->99只鸡

 

 

通信法
package kuang03;

public class TestPc2 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TV tv = new TV();
		new Player(tv).start();
		new Watcher(tv).start();
	}

}

//演员与观众都需要一个tv
//就像producer和consumer都需要一个container


//生产者-->演员
class Player extends Thread{
	TV tv;
	public Player(TV tv) {
		this.tv=tv;
	}
	@Override
	public void run() {
		for(int i=0;i<20;i++) {
//			System.out.println("")
			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<20;i++) {
			tv.watch();
		}
	}
}

//产品-->节目
class TV{
	//演员表演 观众等待 T
	//观众观看 演员等待 F
	
	String voice;//表演的节目
	boolean flag = true;
	
	//表演
	//养成习惯 只要涉及到并发 就直接synchronized
	public synchronized void play(String voice) {
		if(!flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	
		System.out.println("演员表演了:"+voice);
		//通知观众观看
		this.notifyAll();//通知唤醒
		this.voice = voice;
		this.flag = !this.flag;//转换标志位
	}
	
	//观看
	public synchronized void watch() {
		if(flag) {//如果没有表演
			try {//等待演员表演
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		System.out.println("我观看了:"+voice);
		//通知演员表演
		this.notifyAll();
		this.flag = !this.flag;//转换标志位
	}
}


演员表演了:王牌对王牌播放中
我观看了:王牌对王牌播放中
演员表演了:抖音,记录美好生活
我观看了:抖音,记录美好生活
演员表演了:王牌对王牌播放中
我观看了:王牌对王牌播放中
演员表演了:抖音,记录美好生活
我观看了:抖音,记录美好生活
演员表演了:王牌对王牌播放中
我观看了:王牌对王牌播放中
演员表演了:抖音,记录美好生活
我观看了:抖音,记录美好生活
演员表演了:王牌对王牌播放中
我观看了:王牌对王牌播放中
演员表演了:抖音,记录美好生活
我观看了:抖音,记录美好生活
演员表演了:王牌对王牌播放中
我观看了:王牌对王牌播放中
演员表演了:抖音,记录美好生活
我观看了:抖音,记录美好生活
演员表演了:王牌对王牌播放中
我观看了:王牌对王牌播放中
演员表演了:抖音,记录美好生活
我观看了:抖音,记录美好生活
演员表演了:王牌对王牌播放中
我观看了:王牌对王牌播放中
演员表演了:抖音,记录美好生活
我观看了:抖音,记录美好生活
演员表演了:王牌对王牌播放中
我观看了:王牌对王牌播放中
演员表演了:抖音,记录美好生活
我观看了:抖音,记录美好生活
演员表演了:王牌对王牌播放中
我观看了:王牌对王牌播放中
演员表演了:抖音,记录美好生活
我观看了:抖音,记录美好生活
演员表演了:王牌对王牌播放中
我观看了:王牌对王牌播放中
演员表演了:抖音,记录美好生活
我观看了:抖音,记录美好生活

 

线程池

 

在这里插入图片描述

 

img

package kuang03;

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

//测试线程池
public class TestPool {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//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() {
		// TODO Auto-generated method stub
		System.out.println(Thread.currentThread().getName());
	}
}

 

 

总结

创建线程

package kuang03;

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

public class ThreadReview {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new MyThread1().start();
		
		new Thread(new MyThread2()).start();
		
		FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread3());
        												//放Runnable或者Thread都可以
		//       泛型约束							     泛型约束
		new Thread(futureTask).start();
		
		//获取返回值
		try {
			Integer integer = futureTask.get();
			System.out.println((int)integer);
		} catch (InterruptedException | ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

class MyThread1 extends Thread{
	@Override
	public void run() {
		System.out.println("MyThread1");
	}
}

class MyThread2 implements Runnable{
	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("MyThread2");
	}
}

//实现Callable接口
class MyThread3 implements Callable<Integer>{//Callable需要一个返回值
	
	@Override
	public Integer call() throws Exception{
		System.out.println("MyThread3");//方法体
		return 100;//需要一个返回值

	}
}

CopyOnWriteList..Lock.....等

标签:---,Thread,更新,public,学习,线程,new,只鸡
来源: https://www.cnblogs.com/4-Prestar/p/14501805.html