文章目录
多线程
普通方法
只有主线程一条执行路径
多线程
多条执行路径,主程序和子程序并行交替执行
Process(进程)与Thread(线程)
进程 是执行程序的一次执行过程
进程 里面可以有若干个线程但至少会有一个线程
线程不一定执行看cpu调度
线程三种方式Thread类 Runnable接口 collection接口
Thread
//总结:线程开启不一定立即执行,由cpu执行
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();
//调用start方法开启线程
testThread1.start();
//主线程
for (int i = 0; i < 20; i++) {
System.out.println("我在学习多线程"+i);
}
}
}
文件的下载多线程
文件的下载顺序会不一样看方法的调度
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();
try {
webDownloader.downloader(url, name);
System.out.println("下载了文件为"+name);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
TestThread2 t1 = new TestThread2("https://img-home.csdnimg.cn/images/20210924092214.jpg","1.jpg");
TestThread2 t2 = new TestThread2("https://i0.hdslb.com/bfs/feed-admin/d7c2a5fd2d583f246b3ed95c9ea49d9ec60c5371.jpg@880w_388h_1c_95q","2.jpg");
t1.start();
t2.start();
}
}
//下载器
class WebDownloader{
//下载方法
public void downloader(String url,String name) throws IOException {
FileUtils.copyURLToFile(new URL(url),new File(name));
System.out.println("IO异常,downloader方法出现问题");
}
}
Runable接口
public class TestThread2 implements Runnable {
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();
try {
webDownloader.downloader(url, name);
System.out.println("下载了文件为"+name);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
TestThread2 t1 = new TestThread2("https://img-home.csdnimg.cn/images/20210924092214.jpg","1.jpg");
TestThread2 t2 = new TestThread2("https://i0.hdslb.com/bfs/feed-admin/d7c2a5fd2d583f246b3ed95c9ea49d9ec60c5371.jpg@880w_388h_1c_95q","2.jpg");
new Thread(t1).start();
new Thread(t2).start();
}
}
//下载器
class WebDownloader{
//下载方法
public void downloader(String url,String name) throws IOException {
FileUtils.copyURLToFile(new URL(url),new File(name));
System.out.println("IO异常,downloader方法出现问题");
}
}
继承Thread
子类继承Thread类具备多线程能力
启动线程 子类对象.start()
不建议使用避免oop单继承局限
实现Runable
实现接口Runable具备多线程能力
启动程序传入目标对象+Thread对象.start()
推荐使用避免了单继承局限,灵活方便,方便同一个对象被多个线程使用
初始并发
public class Thread4 implements Runnable{
private int ticket = 10;
@Override
public void run() {
while (true){
if (ticket<0) {
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "拿到了第" + ticket-- + "票");
}
}
public static void main(String[] args) {
Thread4 thread4 = new Thread4();
new Thread(thread4,"小明").start();
new Thread(thread4,"老师").start();
new Thread(thread4,"黄牛").start();
}
}
//模拟龟兔
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("兔子")){
try {
Thread.sleep(5);
} 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;
}{
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();
}
}
实现Callable接口
实现Callable接口,需要返回值
重写call方法,需要抛出异常
创建执行服务
提交执行
获取结果
关闭服务
TestCallable t1 = new TestCallable();
TestCallable t2 = new TestCallable();
ExecutorService ser = Executors.newFixedThreadPool(2);
Future<String> r1 = ser.submit(t1);
Future<String> r2 = ser.submit(t2);
String re1 = r1.get();
String re2 = r2.get();
System.out.println(re1);
System.out.println(re2);
ser.shutdown();
静态代理
真实对象和代理对象都要实现同一个接口
代理对象要代理真实对象
好处:
代理对象可以做很多真实对象做不了的事情
真实对象专注做自己的事情
public class StaticProxy {
public static void main(String[] args) {
You you = new You();
// Lambda表达式
new Thread(()-> System.out.println("111")).start();
new WeddingCompany(new You()).HappyMarry();
WeddingCompany weddingCompany = new WeddingCompany(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("结婚前,布置现场");
}
}
public class TestLambda {
//3.静态内部类
static class Like2 implements Ilike{
@Override
public void lambda() {
}
}
public static void main(String[] args) {
Ilike like = new Like();
like.lambda();
like = new Like2();
//局部
class Like3 implements Ilike{
@Override
public void lambda() {
}
}
like = new Like3();
like.lambda();
//5.匿名 没有类的名称,必须借助接口或者类的名称
like = new Ilike() {
@Override
public void lambda() {
System.out.println("4");
}
};
like.lambda();
//6.用lambda
like = ()->{
System.out.println("5");
};
//7.简化
like = ()-> System.out.println("6");
like.lambda();
}
}
interface Ilike{
void lambda();
}
class Like implements Ilike{
@Override
public void lambda() {
System.out.println("I Like");
}
}
总结:
lambda表达式只能有一行代码的情况下才能简化代码,如果有多行,那么就用代码块包裹
前提是接口为函数式接口
多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号
线程五大状态
创建newThread
就绪start
阻塞 sleep wait
运行
dead(中断或结束)
setPriority(int new Priority) 更改优先级
sleep 睡眠
join 等待该线程终止
yield 暂停
interrupt 中断
isAlive 测试
测试stop
1.建议正常停止 —> 利用次数,不建议死循环
2.不建议使用标准位 -->设置一个标致位
3.不要使用stop或者destory等过时或者jdk不建议
public class TestStop implements Runnable {
//设置一个标致位
boolean flag = true;
@Override
public void run() {
int i = 0;
while (flag){
System.out.println("run ... Thread"+i++);
}
}
public void stop(){
this.flag = false;
}
public static void main(String[] args) {
TestStop testStop = new TestStop();
new Thread(testStop).start();
for (int i = 0; i < 1000; i++) {
System.out.println("main"+i);
if (i==900){
testStop.stop();
System.out.println("线程停止了");
}
}
}
}
sleep线程睡眠
模拟倒计时
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<=0){
break;
}
}
}
}
模拟获取当前时间
public class TestSleep3 {
public static void main(String[] args) {
Date time = new Date(System.currentTimeMillis());
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(new SimpleDateFormat("HH:mm:ss").format(time));
time = new Date(System.currentTimeMillis());
}
}
public static void tenDown() throws InterruptedException {
int num = 10;
while (true){
Thread.sleep(1000);
System.out.println(num--);
if (num<=0){
break;
}
}
}
}
线程礼让
让当前的线程暂停,但不阻塞
将线程从运行状态转换为就绪状态
让cpu重新调度,礼让不一定成功!看cup心情
package com.project.thread;
//礼让不一定成功看心情
public class TestYied {
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合并线程
join合并线程,待此线程执行完成后,在执行其他线程,其他线程阻塞
可以想象成插队
package com.project.thread;
//测试join
public class TestJoin implements Runnable {
@Override
public void run() {
for (int i = 0; i < 500; 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 < 1000; i++) {
if (i==200){
thread.join();//插队
}
System.out.println("main"+i);
}
}
}
线程状态
package com.project.thread;
//观察线程状态
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(i);
}
System.out.println("/");
});
Thread.State state = thread.getState();
System.out.println(state);
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);
}
}
}
线程优先级
线程的优先级用数字表示,范围从1-10
getPriority()
setPriority(int xxx)
package com.project.thread;
public class TestPriority extends Thread{
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
MyPriority myPriority = new MyPriority();
Thread t1 = new Thread(myPriority);
Thread t2 = new Thread(myPriority);
Thread t3 = new Thread(myPriority);
Thread t4 = new Thread(myPriority);
Thread t5 = new Thread(myPriority);
Thread t6 = new Thread(myPriority);
//先设置优先级,在启动
t1.start();
t2.setPriority(1);
t2.start();
t3.setPriority(4);
t3.start();
t4.setPriority(Thread.MAX_PRIORITY);
t4.start();
t5.setPriority(8);
t5.start();
t6.setPriority(7);
t6.start();
}
static class MyPriority implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
}
}
}
守护线程
线程分为用户线程和守护线程
虚拟机确保用户线程执行完毕
虚拟机不用等待守护线程执行完毕
package com.project.thread;
public class TestDaemom {
public static void main(String[] args) {
God god = new God();
you you1 = new you();
Thread thread = new Thread(god);
thread.setDaemon(true); //默认是false表示用户线程,正常的线程都是用户线程
thread.start();//上帝守护线程启动
new Thread(you1).start();//用户线程启动
}
}
//上帝
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 < 36500; i++) {
System.out.println("你一生开心活着");
}
System.out.println("====goodbye you");
}
}
线程同步
多个线程操作同一个资源
并发:同一个对象被多个线程同时操作
多线程访问同一个对象叫并发
形成条件:队列+锁
问题解决队列加锁
不安全线程
arraylist
同步方法
由于我们可以通过private关键字保证数据只能被方法访问,所以我们只需要针对方法提出一套机制,这套机制就是synchronized关键字,包括两种方法synchronize方法和synchronize块
pubic synchronize void method(int arges){}
缺陷:加上synchronize会大大影响效率
锁太多就浪费资源所以就有锁块
原理:每个人都要排队,当第一个人拿完了下一个人才可以拿
锁默认锁的是this就是本身
所以就需要同步块
synchronized(Obj){}
Obj称之为同步监视器
JUC并发测试
//测试
public class TestJUC {
public static void main(String[] args) {
CopyOnWriteArrayList<String> copyOnWriteArrayList = new CopyOnWriteArrayList();
for (int i = 0; i < 10000; i++) {
new Thread(() -> {
copyOnWriteArrayList.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(copyOnWriteArrayList.size());
}
}
死锁
多个线程各自占有一些共享资源,并且相互等待其他线程占有的资源才能运行,而导致两个或多个线程都在等待对象释放资源,都停止执行的情形某一个同步块同时拥有“两个以上对象的锁”时,就有肯发生死锁问题
产生死锁条件
互斥条件:一个资源只能被一个进程使用
请求与保持条件:一个进程因请求资源而阻塞是,对已获得的资源保持不放
不剥夺条件:进程已经获得的资源,在未使用完之前,不能强行剥夺
循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
package com.project.thread;
//死锁
public class DeadLock {
public static void main(String[] args) {
Makeup g1 = new Makeup(0,"慧");
Makeup g2 = new Makeup(1,"白");
g1.start();
g2.start();
}
}
class Lipstick{
}
class Mirror{
}
class Makeup extends Thread{
//需要资源只有一份
static Lipstick lipstick = new Lipstick();
static Mirror mirror = new Mirror();
int choice;
String girlName;
Makeup(int choice,String girlName){
this.choice = choice;
this.girlName = girlName;
}
@Override
public void run() {
//化妆
try {
makeup();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void makeup() throws InterruptedException {
if (choice==0){
synchronized (lipstick){
//获得口红的锁
System.out.println(this.girlName+"获得口红的锁");
Thread.sleep(1000);
}
synchronized (mirror){
System.out.println(this.girlName+"获得镜子的锁");
}
} else {
synchronized (mirror){
//获得口红的锁
System.out.println(this.girlName+"获得镜子的锁");
Thread.sleep(2000);
}
synchronized (lipstick){
System.out.println(this.girlName+"获得口红的锁");
}
}
}
}
Lock(锁)
显示定义的锁
synchronize和Lock的对比
Lock是显示锁(手动开启和关闭,别忘记关闭锁)synchronize是隐式锁,出了作用域自动释放
Lock只有代码块锁,synchronize有代码锁和方法锁
使用Lock jvm将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性
使用顺序
Lock 同步代码块 同步方法
package com.project.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestLock {
public static void main(String[] args) {
TestLock2 lock2 = new TestLock2();
new Thread(lock2).start();
new Thread(lock2).start();
new Thread(lock2).start();
}
}
class TestLock2 implements Runnable{
int tick = 10;
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
lock.lock();
if (tick > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(tick--);
}else {
break;
}
} finally {
lock.unlock();
}
}
}
}
生产者和消费者(线程通信)
java提供了几个方法解决线程之间的通信问题
方法名 | 作用 |
---|---|
wait() | 表示线程会一直等待,直到其它线程通知,与sleep不同,会释放锁 |
wait(long timeout) | 指定等待的毫秒数 |
nofity() | 唤醒一个处于等待状态的线程 |
nofityAll() | 唤醒同一个方法上所有调用wait()方法的线程,优先级别高的线程优先度 |
解决方式:
生产者/消费者模式
管程法
package com.project.gaoji;
import javax.swing.plaf.synth.SynthConstants;
//测试:生产者和消费者 -》利用缓冲区解决:管程法
//生产者
public class TestPC {
public static void main(String[] args) {
SynContainer container = new SynContainer();
new Productor(container).start();
new Consumer(container).start();
}
}
//生产者
class Productor extends Thread{
SynContainer container;
public Productor(SynContainer container){
this.container = container;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
container.push(new Chicken(i));
System.out.println("生产了"+i+"只鸡");
}
}
}
//消费者
class Consumer extends Thread{
SynContainer container;
public Consumer(SynContainer container){
this.container = container;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("消费"+container.pop().id+"只鸡");
}
}
}
//鸡
class Chicken{
int id;
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.project.gaoji;
public class Test2 {
public static void main(String[] args) {
TV tv = new TV();
new Player(tv).start();
new Watcher(tv).start();
}
}
//生产者 演员
class Player extends Thread{
TV tv;
public Player(TV tv){
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if (i%2==0){
this.tv.plays("快乐在播放");
}else {
this.tv.plays("抖音:记录美好生活");
}
}
}
}
//消费者 观众
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{
String voice;
boolean flag = true;
public synchronized void plays(String voice){
if (!flag){
try {
this.wait();
} catch (InterruptedException e) {
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) {
e.printStackTrace();
}
}
System.out.println("观众观看"+voice);
this.notifyAll();
this.flag = !this.flag;
}
}
线程池
提高响应速度
降低资源消耗
便于线程管理
ExecutorService和Executors
package com.project.Poll;
import org.apache.ibatis.executor.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestPool {
public static void main(String[] args) {
//线程池大小
ExecutorService service = Executors.newFixedThreadPool(10);
//执行
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
//关闭
service.shutdown();
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("观众观看"+voice);
this.notifyAll();
this.flag = !this.flag;
}
}
### 线程池
提高响应速度
降低资源消耗
便于线程管理
ExecutorService和Executors
package com.project.Poll;
import org.apache.ibatis.executor.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestPool {
public static void main(String[] args) {
//线程池大小
ExecutorService service = Executors.newFixedThreadPool(10);
//执行
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
//关闭
service.shutdown();
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}