Java中的多线程
-
Thread class 继承Thread类(重点)
-
Runnable接口
-
Callable接口
Thread
-
自定义一个线程类继承Thread类
-
重写一个run()方法,编写线程执行体
-
创建线程对象,调用start()方法启动
public class ThreadTest extends Thread{
网图下载
public class TestThread extends Thread {
private String url;//网络图片地址
private String name;//保存的图片名
//构造器
public TestThread(String url,String name){
this.url=url;
this.name=name ;
}
//重写run执行体
-
子类继承Thread类具备多线程能力
-
启动线程:子类对象.start();
-
不建议使用:避免OOP单继承局限性
OOP全称Object Oriented Programming,是指面向对象程序设计,是一种计算机编程架构。OOP 的一条基本原则是计算机程序是由单shu个能够起到子程序作用的单元或对象组合而成。OOP的优缺点:
1、OOP 的优点:使人们的编程与实际的世界更加接近,所有的对象被赋予属性和方法,结果编程就更加富有人性化。
2、OOP 的也有缺点,就 C++ 而言,由于面向更高的逻辑抽象层,使得 C++ 在实现的时候,不得不做出性能上面的牺牲,有时候甚至是致命的 。
实现Runnable接口
-
自定义一个线程类实现Runnable接口
-
重写一个run()方法,编写线程执行体
-
创建线程对象,调用start()方法启动
public class TestThread implements Runnable {
private String url;//网络图片地址
private String name;//保存的图片名
public TestThread(String url,String name){
this.url=url;
this.name=name ;
}
-
实现接口Runnable具有多线程能力
-
启动线程:new Thread对象+传入目标对象.start();
-
推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
多并发
//问题:多线程操作同一个资源的情况下,出现资源紊乱,线程不安全
public class TestThread implements Runnable {
private Integer ticketNum = 10;//车票
龟兔赛跑--RACE
public class Race implements Runnable{
private static String winner;
实现Callable接口
-
实现Callable接口,需要返回值类型
-
重写call方法,需要 抛出异常
-
创建目标对象
-
创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
-
提交执行:Future<Boolean> result1 = ser.submit(t1);
-
获取结果:boolean r1 = result1.get();
-
关闭服务:ser.shutdownNow();
public class TestCallable implements Callable {
private String url;//网络图片地址
private String name;//保存的图片名
public TestCallable(String url,String name){
this.url=url;
this.name=name ;
}
静态代码模式
静态代码模式总结:
-
真实对象和代理对象都要实现同一个接口
-
代理对象要代理真实角色
-
好处
-
代理对象可以做很多真实对象做不了的事情
-
真实对象专注做自己的事情
-
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{
Lambda表达式
-
避免匿名内部类定义过多
-
其实质属于函数式编程概念
-
函数式接口
-
任何接口,如果只包含一个抽象类,那么它就是函数式接口
-
对于函数式接口我们可以用Lambda表达式来创建接口对象
-
推导Lambda表达式
public class TestLambda {
//静态内部类
static class Like2 implements ILike{
线程五大状态
线程方法
| 方法 | 说明 |
|---|---|
| setPriority(int new Priority) | 更改线程的优先级 |
| static void sleep(long mills) | 在指定的毫秒数内让当前正在执行的线程体休眠 |
| void join() | 等待该线程终止 |
| static void yield() | 暂停当前正在执行的线程对象,并执行其他线程 |
| void interrupt() | 中断线程,别用这个方法 |
| boolean isAlive() | 测试线程是否属于活动状态 |
停止线程
-
不推荐使用JDK提供的stop()、destory()方法。
-
推荐使用自己停下来
-
建议使用一个标志位进行终止变量,当flag=false,线程停止
public class TestStop implements Runnable{
//设置一个标志位
private boolean flag = true;
线程休眠
-
sleep(时间)指定当前线程阻塞的毫秒差
-
sleep存在异常InterruptedException;
-
sleep时间达到后线程进入就绪状态;
-
sleep可以模拟网络延时,倒计时等;
-
每一个对象都有一个锁,sleep不会释放锁
public class TestSleep implements Runnable {
private Integer ticketNum = 10;//车票
public class TestSleep {
//模拟倒计时
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<=0){
break;
}
}
}
}
public class TestSleep {
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();
}
}
}
}
线程礼让
-
礼让线程,让正在运行的线程暂停,但不阻塞
-
让线程从运行状态变为就绪状态
-
让CPU重新调度,礼让看CPU,不一定能成功
public class TestYield {
public static void main(String[] args) {
txtYield txtYield = new txtYield();
new Thread(txtYield,"a").start();
new Thread(txtYield,"b").start();
}
}
class txtYield implements Runnable{
线程强制执行
-
Join合并线程,待此线程执行完毕后再执行其他线程,其他线程阻塞
-
可以理解为VIP不用排队
public class TestJoin implements Runnable{
线程状态观测
-
线程状态
线程可以处于以下状态之一:
-
尚未启动的线程处于此状态。
-
在Java虚拟机中执行的线程处于此状态。
-
被阻塞等待监视器锁定的线程处于此状态。
-
正在等待另一个线程执行特定动作的线程处于此状态。
-
正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。
-
已退出的线程处于此状态。
-
public class TestThreadState {
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);
}
}
}
线程的优先级
public class TestPriority {
public static void main(String[] args) {
//主线程默认优先级
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
MyPriority myPriority = new MyPriority();
Thread thread1 = new Thread(myPriority,"a");
Thread thread2 = new Thread(myPriority,"b");
Thread thread3 = new Thread(myPriority,"c");
Thread thread4 = new Thread(myPriority,"d");
Thread thread5 = new Thread(myPriority);
Thread thread6 = new Thread(myPriority);
//先设置优先级,再启动
thread1.start();
thread2.setPriority(1);
thread2.start();
thread3.setPriority(3);
thread3.start();
thread4.setPriority(Thread.MAX_PRIORITY);//MAX_PRIORITY=10
thread4.start();
}
}
class MyPriority implements Runnable{
守护线程Daemon
-
线程分为守护线程和用户线程
-
虚拟机必须确保用户线程执行完毕
-
虚拟机不用等待守护线程执行完毕
-
像后台记录操作日志,监控录像,垃圾回收等
public class TestDaemon {
public static void main(String[] args) {
God god = new God();
YouLive you = new YouLive();
Thread thread = new Thread(god);
thread.setDaemon(true);//默认是false,默认是用户线程
thread.start();//上帝线程
new Thread(you).start();//you
}
}
class God implements Runnable{
线程同步机制
-
并发:同一对象被多个线程同时操作
-
线程同步其实是一个等待机制,多个需要同时访问这个对象的线程进入这个对象的等待池进行排列
-
队列和锁
-
锁机制:synchronized
-
加锁引起延时等性能问题,也会导致性能倒置
-
三大不安全案例
public class UnsafeTicket {
public static void main(String[] args) {
BuyTicket buyTicket = new BuyTicket();
new Thread(buyTicket,"我").start();
new Thread(buyTicket,"你").start();
new Thread(buyTicket,"黄牛").start();
}
}
class BuyTicket implements Runnable{
private int ticketNums = 10;//票数
private boolean flag = true;
//买票
private void buy(){
if (ticketNums<=0){
flag = false;
return;
}
System.out.println(Thread.currentThread().getName()+"拿到了"+ticketNums--);
}
public class UnsafeBank {
public static void main(String[] args) {
Account acc = new Account(100, "育儿基金");
Bank you = new Bank(acc, "你", 50);
Bank girlFriend = new Bank(acc, "女朋友", 100);
you.start();
girlFriend.start();
}
}
//模拟账户
class Account{
int money;
String name;
public Account(int money, String name) {
this.money = money;
this.name = name;
}
}
//模拟银行
class Bank extends Thread{
Account account;
int handMoney;
int drawingMoney;
public Bank(Account account, String name, int drawingMoney) {
super(name);
this.account = account;
this.drawingMoney = drawingMoney;
}
//判断取钱模式
//线程不安全的集合
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(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
同步方法及同步块
如上代码加锁
public class UnsafeTicket {
public static void main(String[] args) {
BuyTicket buyTicket = new BuyTicket();
new Thread(buyTicket,"我").start();
new Thread(buyTicket,"你").start();
new Thread(buyTicket,"黄牛").start();
}
}
class BuyTicket implements Runnable{
private int ticketNums = 10;//票数
private boolean flag = true;
//买票
private synchronized void buy(){
if (ticketNums<=0){
flag = false;
return;
}
System.out.println(Thread.currentThread().getName()+"拿到了"+ticketNums--);
}
public class UnsafeBank {
public static void main(String[] args) {
Account acc = new Account(100, "育儿基金");
Bank you = new Bank(acc, "你", 50);
Bank girlFriend = new Bank(acc, "女朋友", 100);
you.start();
girlFriend.start();
}
}
//模拟账户
class Account{
int money;
String name;
public Account(int money, String name) {
this.money = money;
this.name = name;
}
}
//模拟银行
class Bank extends Thread{
Account account;
int handMoney;
int drawingMoney;
public Bank(Account account, String name, int drawingMoney) {
super(name);
this.account = account;
this.drawingMoney = drawingMoney;
}
//判断取钱模式
//方法块没加上
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());
}
}
CopyOnWriteArrayList
死锁
-
互斥条件:一个资源每次只能被一个进程使用。
-
请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
-
不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。
-
循环等待条件:若干个进程之间形成一种头尾相接的循环等待资源关系。
public class DeadLock {
public static void main(String[] args) {
MakeUp mak1 = new MakeUp(0, "雪儿");
MakeUp mak2 = new MakeUp(1, "紫儿");
mak1.start();
mak2.start();
}
}
class Lipstick{}//口红
class Mirror{}//镜子
class MakeUp extends Thread{
//确保资源只有一份
static Lipstick lipstick = new Lipstick();
static Mirror mirror = new Mirror();
int choice;
String girl;
MakeUp(int choice,String girl){
this.choice=choice;
this.girl=girl;
}
Lock锁
-
从JDK5.0开始,Java提供了更加强大的线程同步机制--通过显示定义同步锁对象来实现同步。同步锁使用Lock对象充当
-
java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象
-
ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显示加锁、释放锁
public class TestLock {
public static void main(String[] args) {
TestLock2 testLock2 = new TestLock2();
new Thread(testLock2).start();
}
}
class TestLock2 implements Runnable{
int ticketNums=10;
//定义Lock
private final ReentrantLock lock = new ReentrantLock();
生产者和消费者的问题
线程通信:
-
应用场景:生产者------>仓库------>消费者
-
分析,生产者和消费者共享一个资源,并相互依赖,互为条件。
-
在这个问题中,仅仅用synchronized是不够的
-
synchronized可阻止并发更新同一个共享资源,实现了同步
-
synchronized不能用来实现不同线程之间的信息传递(通信)
-
管程法
//测试:生产消费者模型-->利用缓冲区解决:管程法
//生产者 消费者 缓存区 产品
public class TestPC {
public static void main(String[] args) {
SynContainer synContainer = new SynContainer();
new Producer(synContainer).start();
new Consumer(synContainer).start();
}
}
//生产者
class Producer extends Thread{
SynContainer container;//定义容器
public Producer(SynContainer container) {
this.container = container;
}