多线程
程序、进程、线程
程序
程序是指令和数据的有序集合,是一个静态的概念
进程(process)
进程是程序的一次执行过程,是动态的概念,是系统资源分配的单位
线程(Thread)
通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,线程是CPU调度和执行的单位
main()称为主线程,为系统的入口,用于执行整个程序
线程三种创建方式
继承Thread类
package com.henry.thread;
//继承Thread类,重写run方法,调用start开启线程
public class TestThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("x+"+i);
}
}
public static void main(String[] args) {
//创建一个线程对象
TestThread testThread = new TestThread();
//调用start方法开启线程,调用run方法不会并行执行,会顺序执行
testThread.start();
//main线程,主线程
for (int i = 0; i < 1000 ; i++) {
System.out.println("y+"+i);
}
}
}
多线程下载图片
package com.henry.thread;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class TestThread2 extends Thread{
private String url;
private String filename;
public TestThread2(String url, String filename) {
this.url = url;
this.filename = filename;
}
@Override
public void run() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url,filename);
System.out.println("下载了文件名为:"+filename);
}
public static void main(String[] args) {
TestThread2 t1 = new TestThread2("https://img2020.cnblogs.com/blog/2035046/202008/2035046-20200829165338623-1016877944.png","1.png");
TestThread2 t2 = new TestThread2("https://img2020.cnblogs.com/blog/2035046/202008/2035046-20200829170405010-1982825617.png","2.png");
TestThread2 t3 = new TestThread2("https://pic.cnblogs.com/avatar/2035046/20200511235307.png","3.png");
t1.start();
t2.start();
t3.start();
//下载了文件名为:2.png
//下载了文件名为:1.png
//下载了文件名为:3.png
}
}
class WebDownloader{
public void downloader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
}
}
}
实现Runnable接口
package com.henry.thread;
//创建线程方式2:实现runnable接口,重写run方法,执行线程需要runnable接口实现类
public class TestThread3 implements Runnable{
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("x+"+i);
}
}
public static void main(String[] args) {
//创建runnable接口的实现类对象
TestThread3 testThread3 = new TestThread3();
//创建线程对象,通过线程对象开启我们的线程
new Thread(testThread3).start();
for (int i = 0; i < 1000 ; i++) {
System.out.println("y+"+i);
}
}
}
多线程下载图片
package com.henry.thread;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class TestThread2 implements Runnable{
private String url;
private String filename;
public TestThread2(String url, String filename) {
this.url = url;
this.filename = filename;
}
public void run() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url,filename);
System.out.println("下载了文件名为:"+filename);
}
public static void main(String[] args) {
TestThread2 t1 = new TestThread2("https://img2020.cnblogs.com/blog/2035046/202008/2035046-20200829165338623-1016877944.png","1.png");
TestThread2 t2 = new TestThread2("https://img2020.cnblogs.com/blog/2035046/202008/2035046-20200829170405010-1982825617.png","2.png");
TestThread2 t3 = new TestThread2("https://pic.cnblogs.com/avatar/2035046/20200511235307.png","3.png");
new Thread(t1).start();
new Thread(t2).start();
new Thread(t3).start();
//下载了文件名为:2.png
//下载了文件名为:1.png
//下载了文件名为:3.png
}
}
class WebDownloader{
public void downloader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
}
}
}
实现Callable接口
package com.henry.thread;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
public class TestThread2 implements Callable<Boolean> {
private String url;
private String filename;
public TestThread2(String url, String filename) {
this.url = url;
this.filename = filename;
}
public Boolean call() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url,filename);
System.out.println("下载了文件名为:"+filename);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestThread2 t1 = new TestThread2("https://img2020.cnblogs.com/blog/2035046/202008/2035046-20200829165338623-1016877944.png","1.png");
TestThread2 t2 = new TestThread2("https://img2020.cnblogs.com/blog/2035046/202008/2035046-20200829170405010-1982825617.png","2.png");
TestThread2 t3 = new TestThread2("https://pic.cnblogs.com/avatar/2035046/20200511235307.png","3.png");
//创建执行服务
ExecutorService service = Executors.newFixedThreadPool(3);
//提交执行
Future<Boolean> r1 = service.submit(t1);
Future<Boolean> r2 = service.submit(t2);
Future<Boolean> r3 = service.submit(t3);
//获取结果
Boolean rb1 = r1.get();
Boolean rb2 = r2.get();
Boolean rb3 = r3.get();
//关闭服务
service.shutdownNow();
}
}
class WebDownloader{
public void downloader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
}
}
}
龟兔赛跑问题
package com.henry.thread;
public class Race implements Runnable{
private String winner;
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();
}
}
并发问题(资源)
// 多个线程操作同一个对象
// 多个线程操作同一个资源,线程不安全,数据不一致
public class TestThead2 implements Runnable{
// 票数
private int ticket = 10;
public void run() {
while (true) {
if(ticket < 1)
break;
// 延时
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"拿到了"+ticket--);
}
}
public static void main(String[] args) {
TestThead2 testThead2 = new TestThead2();
new Thread(testThead2,"S").start();
new Thread(testThead2,"A").start();
new Thread(testThead2,"H").start();
}
}
静态代理模式
真实对象和代理对象都要实现同一个接口,代理对象代理真实对象
package com.henry;
public class StaticProxy {
public static void main(String[] args) {
new Thread(()-> System.out.println("来了")).start();
new Company(new Peo()).HappyMarry();
}
}
interface Marry{
void HappyMarry();
}
// 真实角色
class Peo implements Marry {
public void HappyMarry() {
System.out.println("peo要结婚了");
}
}
// 代理角色
class Company implements Marry{
// 真实代理角色
private Peo target;
public Company(Peo target) {
this.target = target;
}
public void HappyMarry() {
before();
target.HappyMarry();
after();
}
private void before() {
System.out.println("结婚前准备");
}
private void after() {
System.out.println("结账");
}
}
lamda表达式
函数式接口:接口只包含唯一一个抽象方法
package com.henry;
public class lamdaTest {
public static void main(String[] args) {
Peo p = new like();
p.lamda();
// 匿名内部类
p = new Peo() {
@Override
public void lamda() {
System.out.println("aa");
}
};
p.lamda();
// lamda
p = ()-> System.out.println("bb");
p.lamda();
}
}
interface Peo{
void lamda();
}
class like implements Peo {
@Override
public void lamda() {
System.out.println("henry");
}
}
带参数的
public class LamdaTest2 {
public static void main(String[] args) {
Ha h = new Hen();
h.ha("aa");
h = new Ha() {
@Override
public void ha(String s) {
System.out.println(s);
}
};
h.ha("nn");
h = (String s)-> {
System.out.println(s);
};
h.ha("kk");
// 简化去掉参数类型
h = (s)-> {
System.out.println(s);
};
// 去掉花括号,仅限于一行代码
h = (s)-> System.out.println(s);
}
}
interface Ha{
void ha(String s);
}
class Hen implements Ha{
@Override
public void ha(String s) {
System.out.println(s);
}
}
线程状态
线程停止
// 建议线程正常停止
// 不要使用stop或者destroy
public class TestStop implements Runnable{
// 设置一个标志
private boolean flag = true;
public void run() {
int i = 0;
while (flag) {
System.out.println("进行==="+i++);
}
}
// 修改标志位
public void stop() {
flag = false;
}
public static void main(String[] args) {
TestStop testStop = new TestStop();
new Thread(testStop).start();
for (int i = 0; i < 300; i++) {
System.out.println("main"+i);
if(i == 200){
testStop.stop();
System.out.println("停止");
}
}
}
}
线程休眠
sleep时间到达以后线程进入就绪状态
sleep可以模拟网络延时,倒计时等
每个对象都有一个锁,sleep不会释放锁
// 多个线程操作同一个对象
// 多个线程操作同一个资源,线程不安全,数据不一致
public class TestThead2 implements Runnable{
// 票数
private int ticket = 10;
public void run() {
while (true) {
if(ticket < 1)
break;
// 延时
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"拿到了"+ticket--);
}
}
public static void main(String[] args) {
}
}
倒计时功能
public class TestSleep2 {
public static void main(String[] args) throws InterruptedException {
//tenDown();
Date date = new Date(System.currentTimeMillis());
while (true) {
System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
Thread.sleep(1000);
date = new Date(System.currentTimeMillis());
}
}
// 倒计时
public static void tenDown() throws InterruptedException {
int num = 10;
while(true) {
System.out.println(num--);
Thread.sleep(1000);
if (num <= 0) {
break;
}
}
}
}
线程礼让
让当前正在执行的线程暂停,但不阻塞
将线程从运行状态变为就绪状态
然后cpu会根据调度算法重新调度
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 {
public void run() {
System.out.println(Thread.currentThread().getName()+"开始执行");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"停止执行");
}
}
线程强制执行join(插队)
守护线程
-
线程分为用户线程和守护线程
-
虚拟机必须保证用户线程执行完毕
-
虚拟机不用等待守护线程执行完毕
-
可以用来后台记录日志、监控内存、垃圾回收
thread.setDaemon(true)
线程同步机制
处理多线程问题时,多个线程访问同一个对象,有的线程还想修改这个对象,需要线程同步,线程同步是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列
为了保证数据被访问时候的正确性,在访问时加入锁机制synchronized,当一个对象获得对象的排它锁,独占资源其他线程必须等待
问题:
死锁
产生死锁的条件:互斥、请求保持、不可剥夺、循环等待
public class Lock {
public static void main(String[] args) {
getSource g1 = new getSource(1,"aa");
getSource g2 = new getSource(2,"bb");
// 会锁住
g1.start();
g2.start();
}
}
// 资源1
class S1{
}
// 资源2
class S2{
}
class getSource extends Thread{
// 用static保证每个资源只有一份
static S1 s1 = new S1();
static S2 s2 = new S2();
private int choice;
private String name;
getSource(int choice, String name) {
this.choice = choice;
this.name = name;
}
@Override
public void run() {
try {
getS();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void getS() throws InterruptedException {
if(choice == 1) {
synchronized (s1) {
System.out.println(this.name+"获得s1");
Thread.sleep(1000);
synchronized (s2) {
System.out.println(this.name+"获得s2");
}
}
} else {
synchronized (s2) {
System.out.println(this.name+"获得s2");
Thread.sleep(2000);
synchronized (s1) {
System.out.println(this.name+"获得s1");
}
}
}
}
}
修改同步代码,不会锁住
private void getS() throws InterruptedException {
if(choice == 1) {
synchronized (s1) {
System.out.println(this.name+"获得s1");
Thread.sleep(1000);
}
synchronized (s2) {
System.out.println(this.name+"获得s2");
}
} else {
synchronized (s2) {
System.out.println(this.name+"获得s2");
Thread.sleep(2000);
}
synchronized (s1) {
System.out.println(this.name+"获得s1");
}
}
}
Lock锁
public class TestLock {
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 {
private int number = 10;
// 定义lock锁
private final ReentrantLock lock = new ReentrantLock();
public void run() {
while (true) {
try {
// 加锁
lock.lock();
if(number > 0) {
Thread.sleep(1000);
System.out.println(number--);
} else {
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 解锁
lock.unlock();
}
}
}
}
用synchronized
public void run() {
while (true) {
synchronized ("") {
if(number > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(number--);
} else {
break;
}
}
}
}
生产者和消费者
缓冲区(管程法)
public class TestPC {
public static void main(String[] args) {
Container container = new Container();
new Producer(container).start();
new Consumer(container).start();
}
}
// 生产者
class Producer extends Thread {
Container container;
public Producer(Container container) {
this.container = container;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("生产了"+i);
try {
container.push(new Product(i));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// 消费者
class Consumer extends Thread {
Container container;
public Consumer(Container container) {
this.container = container;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("消费了"+i);
try {
container.pop();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// 产品
class Product {
private int id;
public Product(int id) {
this.id = id;
}
}
// 缓冲区
class Container {
// 容器
Product[] products = new Product[10];
// 计数器
int count = 0;
// 生产者放入产品
public synchronized void push(Product product) throws InterruptedException {
if (count == products.length) {
// 通知消费者消费,生产等待
this.wait();
}
products[count++] = product;
// 通知消费者消费
this.notifyAll();
}
// 消费者消费产品
public synchronized Product pop() throws InterruptedException {
// 判断是否可以消费
if (count == 0) {
// 等待生产者生产,消费者等待
this.wait();
}
count--;
this.notifyAll();
return products[count];
}
}
信号灯法
标志位
public class TestPC2 {
public static void main(String[] args) {
TV tv = new TV();
new actor(tv).start();
new Watcher(tv).start();
}
}
// 生产者--演员
class actor extends Thread {
TV tv;
public actor(TV tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if(i%2 == 0) {
this.tv.play("开始节目"+i);
} 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++) {
this.tv.watch();
}
}
}
// 产品--节目
class TV {
String film;
boolean flag = true;
// 表演
public synchronized void play(String film) {
if(!flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("表演了"+film);
// 通知观众观看
this.notifyAll();
this.film = film;
this.flag = !this.flag;
}
// 观看
public synchronized void watch() {
if(flag) {
// 等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
System.out.println("观看了"+film);
// 通知表演
this.notifyAll();
this.flag = !this.flag;
}
}
}
线程池
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.shutdown();
}
}
class myThread implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}