三种创建Thread方式
- Thread class
- Runnable 接口
- callable 接口
run() 和start的区别
- run只有主线程一条执行路径
- start多条执行路径,主线程和子线程并行交替执行
继承Thread
使用common.io下载图片
package thread;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
/**
* @author by whs
* @date 2020/12/20.
*/
public class TestThread2 extends Thread {
private String url;
private String file;
public TestThread2(String url,String file){
this.url = url;
this.file= file;
}
@Override
public void run() {
WebDownload webDownload = new WebDownload();
webDownload.download(url,file);
System.out.println("下载了图片"+file);
}
public static void main(String[] args) {
TestThread2 testThread2 = new TestThread2("https://tse3-mm.cn.bing.net/th/id/OIP.bLx51CquIR2c5rp7BN1GjwHaLI?w=182&h=274&c=7&o=5&dpr=1.25&pid=1.7","2.jpg");
TestThread2 testThread3 = new TestThread2("https://tse3-mm.cn.bing.net/th/id/OIP.bLx51CquIR2c5rp7BN1GjwHaLI?w=182&h=274&c=7&o=5&dpr=1.25&pid=1.7","3.jpg");
TestThread2 testThread4 = new TestThread2("https://tse3-mm.cn.bing.net/th/id/OIP.bLx51CquIR2c5rp7BN1GjwHaLI?w=182&h=274&c=7&o=5&dpr=1.25&pid=1.7","4.jpg");
testThread2.start();
testThread3.start();
testThread4.start();
}
}
class WebDownload{
public void download(String url,String file){
try {
FileUtils.copyURLToFile(new URL(url),new File(file));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO 异常,download方法出现问题");
}
}
}
实现Runnable
package thread;
/**
* @author by whs
* @date 2020/12/20.
*/
public class TestRunnable implements Runnable {
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("我在看代码" + i);
}
}
public static void main(String[] args) {
ThreadTest threadTest = new ThreadTest();
new Thread(threadTest).start();
for (int i = 0; i < 20; i++) {
System.out.println("我在学习多线程" + i);
}
}
}
- 继承Thread
- 启动线程:子类对象.start()
- 不建议使用:避免OOP单继承局限性
- 实现Runnable接口
- 实现接口Runnable具有多线程能力
- 启动线程:传入目标对象+Thread对象.start()。
- 推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用。
实现Callable
package thread;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
/**
* @author by whs
* @date 2020/12/20.
*/
public class TestCallable implements Callable<Boolean> {
private String url;
private String file;
public TestCallable(String url,String file){
this.url = url;
this.file= file;
}
public Boolean call() throws Exception {
WebDownload2 webDownload2 = new WebDownload2();
webDownload2.download(url,file);
System.out.println("下载了图片"+file);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestCallable testThread2 = new TestCallable("https://tse3-mm.cn.bing.net/th/id/OIP.bLx51CquIR2c5rp7BN1GjwHaLI?w=182&h=274&c=7&o=5&dpr=1.25&pid=1.7","2.jpg");
TestCallable testThread3 = new TestCallable("https://tse3-mm.cn.bing.net/th/id/OIP.bLx51CquIR2c5rp7BN1GjwHaLI?w=182&h=274&c=7&o=5&dpr=1.25&pid=1.7","3.jpg");
TestCallable testThread4 = new TestCallable("https://tse3-mm.cn.bing.net/th/id/OIP.bLx51CquIR2c5rp7BN1GjwHaLI?w=182&h=274&c=7&o=5&dpr=1.25&pid=1.7","4.jpg");
//创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
//执行
Future<Boolean> submit1 = executorService.submit(testThread2);
Future<Boolean> submit2 = executorService.submit(testThread2);
Future<Boolean> submit3 = executorService.submit(testThread2);
//获取结果
boolean b = submit1.get();
boolean b1 = submit2.get();
boolean b2 = submit3.get();
//关闭线程池
executorService.shutdown();
}
}
class WebDownload2{
public void download(String url,String file){
try {
FileUtils.copyURLToFile(new URL(url),new File(file));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO 异常,download方法出现问题");
}
}
}
静态代理
静态代理
package proxy;
/**
* @author by whs
* @date 2020/12/20.
*/
public class TestProxy {
public static void main(String[] args) {
You you = new You();
weddingFactory weddingFactory = new weddingFactory(you);
weddingFactory.HappyMarry();
}
}
//结婚接口
interface Marry{
public void HappyMarry();
}
//你结婚实现类
class You implements Marry{
public void HappyMarry() {
System.out.println("开心的结婚");
}
}
//婚庆公司代理类
class weddingFactory implements Marry{
private Marry marry;
public weddingFactory(Marry marry){
this.marry = marry;
}
public void HappyMarry() {
before();
this.marry.HappyMarry();
after();
}
private void after() {
System.out.println("收尾款");
}
private void before() {
System.out.println("布置场景");
}
}
lamda表达式
-
避免匿名内部类定义过多
-
可以让你的代码看起开很简洁
-
去掉一堆没有意义的代码,只留下核心的逻辑
(params) ->expression[表达式]
(params) ->statement[语句]
(params) ->{statements} -
函数式接口的定义:
- 任何接口,如果只包含唯一一个抽象方法,那么他就是一个函数式接口
- 对于函数式接口,我们可以通过lamda表达式来创建该接口的对象
package lambda;
import javax.sound.midi.Soundbank;
/**
* @author by whs
* @date 2020/12/20.
*/
public class TestLambda {
/*静态内部类*/
static class Like2 implements ILike{
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{
public void lambda() {
System.out.println("i like lambda3");
}
}
like = new Like3();
like.lambda();
/*匿名内部类*/
like = new ILike(){
public void lambda() {
System.out.println("i like lambda4");
}
};
like.lambda();
/*lambda表达式*/
like = () ->{
System.out.println("i like lambda5");
};
like.lambda();
}
}
//ILike接口
interface ILike{
public void lambda();
}
//Like实现类
class Like implements ILike{
public void lambda() {
System.out.println("i like lambda");
}
}
线程五大状态
- new Thread t = new Thread()线程对象一旦创建就到新生状态
- 就绪状态 当调用start()方法,线程立即进入就绪状态,但并不意味着立即调度执行
- 运行状态 进入运行状态,线程才真正执行线程体的代码块
- 阻塞状态 当调用sleep,wait或者同步锁定时,线程进入阻塞状态,就是代码不往下执行,阻塞事件解除后,重新进入就绪状态,等待cpu调度执行
- dead 线程中断,一旦进入死亡状态,就不能再次启动了。
每隔一秒打印时间
package thread;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author by whs
* @date 2020/12/20.
*/
public class TestSleep {
public static void main(String[] args) {
Date date = new Date(System.currentTimeMillis());
while(true){
try {
Thread.sleep(1000);
System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
date = new Date(System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
join
- join 合并线程,待此线程执行完后,在执行其他线程,其他线程阻塞
- 可以想象为插队
线程优先级
- setPriority(int XXX) ;设置优先级
- getPriority(int xxx) ;得到优先级
- 设置优先级建议在start()调度前
Thread.MIN_PRIORITY =1;
Thread.MAX_PRIORITY=10;
Thread.NORM_PRIORITY=5
线程不安全
银行取钱
package thread;
/**
* @author by whs
* @date 2020/12/21.
*/
public class UnsafeBank {
public static void main(String[] args) {
Account account = new Account(100, "基金");
Thread thread = new Drawing(account, 100, "you");
Thread thread1 = new Drawing(account, 50, "girlFriend");
thread.start();
thread1.start();
}
}
//账号类
class Account{
private int money;
private String name;
public Account(int money,String name){
this.money = money;
this.name = name;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Drawing extends Thread{
private Account account;
private int drawingMoney;
private int nowMoney;
public Drawing(Account account ,int drawingMoney ,String name){
super(name);
this.account = account;
this.drawingMoney = drawingMoney;
}
@Override
public void run() {
//取钱
if((account.getMoney() - drawingMoney)<0){
System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
return ;
}
//模拟网络延时
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.setMoney(account.getMoney()-drawingMoney);
nowMoney = nowMoney + drawingMoney;
System.out.println(account.getName()+ "余额为:"+account.getMoney());
System.out.println(this.getName()+"手里的钱"+nowMoney);
}
}
list中添加线程
package thread;
import java.util.ArrayList;
import java.util.List;
/**
* @author by whs
* @date 2020/12/21.
*/
public class TestListThread {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(9000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
同步方法
就是synchronized关键字,它包括两种用法,synchronized方法和synchronized块
- 同步方法 :public synchronized void method(int age){}
synchronized方法控制“对象”的访问,每一个对象对应一把锁,每个synchronized方法都必须获取调用该方法的对象的锁才行,否者进程阻塞,方法一旦执行,就独占锁,知道方法返回才释放锁,后面被阻塞的线程才能获得锁,继续执行。
- 缺陷: 若将大的方法申明为synchronized将会影响效率
银行取钱(synchronized)
package thread;
/**
* @author by whs
* @date 2020/12/21.
*/
public class UnsafeBank {
public static void main(String[] args) {
Account account = new Account(1000, "基金");
Thread thread = new Drawing(account, 100, "you");
Thread thread1 = new Drawing(account, 50, "girlFriend");
thread.start();
thread1.start();
}
}
//账户类
class Account{
private int money;
private String name;
public Account(int money,String name){
this.money = money;
this.name = name;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Drawing extends Thread{
private Account account;
private int drawingMoney;
private 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.getMoney() - drawingMoney)<0){
System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
return;
}
//模拟网络延时
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.setMoney(account.getMoney()-drawingMoney);
nowMoney = nowMoney + drawingMoney;
System.out.println(account.getName()+ "余额为:"+account.getMoney());
System.out.println(this.getName()+"手里的钱"+nowMoney);
}
}
}
list问题(synchronized)
package thread;
import java.util.ArrayList;
import java.util.List;
/**
* @author by whs
* @date 2020/12/21.
*/
public class TestListThread {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
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());
}
}
idea快捷键
- Ctrl+Shift+上下键 上下移动代码
juc版
package thread;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* @author by whs
* @date 2020/12/21.
*/
public class TestJuc {
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(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
synchronize和Lock的对比
- Lock是显示锁(手动开启和关闭锁)synchronized是隐式锁,出了作用域自动释放
- Lock只有代码块锁,synchronized有代码块锁和方法锁
- 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性
- 有限使用顺序:
- Lock > 同步代码块(已经进入方法体,分配了相应的资源) > 同步方法(在方法体外)
线程通信
- wait() 表示线程一直等待,直到其他线程通知,与sleep不同,会释放锁
- wait(long timeout ) 指定等待的毫秒数
- notify() 唤醒一个处于等待状态的线程
- notifyAll() 唤醒同一个对象上所有调用wait()方法的线程,优先级级别高的线程先的调度
注意:均是Object类的方法,都只能在同步方法或者同步代码块中使用,否则会抛出异常ILLegalMonitorStateException
管程法
package thread;
/**
* @author by whs
* @date 2020/12/21.
*/
public class TestPip {
public static void main(String[] args) {
SynContainer container = new SynContainer();
new Producter(container).start();
new Cousumer(container).start();
}
}
//生产者
class Producter extends Thread{
SynContainer synContainer;
public Producter(SynContainer synContainer){
this.synContainer = synContainer;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
synContainer.push(new Chicken(i));
System.out.println("生产了第"+ i+ "只鸡");
}
}
}
//消费者
class Cousumer extends Thread{
SynContainer synContainer;
public Cousumer(SynContainer synContainer){
this.synContainer = synContainer;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("消费了第"+ synContainer.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();
System.out.println(chickens.length);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果没满,就需要丢入产品
chickens[count] = chicken;
count++;
//通知消费
this.notify();
}
public synchronized Chicken pop(){
if(count == 0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果可以消费
count--;
Chicken chicken = chickens[count];
this.notify();
return chicken;
}
}
线程池
package thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author by whs
* @date 2020/12/21.
*/
public class TestPool {
public static void main(String[] args) {
//创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
//执行线程
executorService.execute(new MyThread());
executorService.execute(new MyThread());
executorService.execute(new MyThread());
executorService.execute(new MyThread());
//关闭线程池
executorService.shutdown();
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() );
}
}
本文是学习完秦疆的大佬的视频做的笔记,如有错误欢迎指正