java 多线程
同步与异步&并发与并行
- 同步:排队执行,效率低却安全
- 异步:同时执行,效率高却不安全
- 并发:同一时间段内发生的多个事件
- 并行:同一时刻发生的多个事件
继承Thread&实现Runnable
public class MyThread extends Thread {
//run方法就是线程要执行的任务方法
@Override
public void run() {
//这里的代码就是一条新的执行路径
//这个执行路径是触发方式,不是调用run方法,而是通过thread对象的start方法来启动任务
for (int i = 0; i < 10; i++) {
System.out.println("锄禾日当午"+i);
}
}
}
public class MyRunnable implements Runnable{
@Override
public void run() {
//线程的任务
for (int i = 0; i < 10; i++) {
System.out.println("锄禾日当午"+i);
}
}
}
public class Demo1 {
public static void main(String[] args) {
MyThread m = new MyThread();
m.start();
for (int i = 0; i < 10; i++) {
System.out.println("汗滴禾下土"+i);
}
//----------------------
new Thread(){
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("12345"+i);
}
}
}.start();
for (int i = 0; i < 10; i++) {
System.out.println("汗滴禾下土"+i);
}
//--------------------------
//实现runnable
//1 创建一个任务对象
MyRunnable r = new MyRunnable();
//创建一个线程并给他一个任务
Thread t = new Thread(r);
//启动线程
t.start();
for (int i = 0; i < 10; i++) {
System.out.println("汗滴禾下土"+i);
}
}
}
实现Runnable与继承Thread相比有如下优势:
1.通过创建任务,然后给线程分配任务的方式实现多线程,更适合多个线程同时执行任务的情况
2.可以避免单继承所带来的局限性
3.任务与线程是分离的,提高了程序的健壮性
4.后期学习的线程池技术,接受Runnable类型的任务,不接受Thread类型的线程
设置和获取线程名称
public class Demo3 {
public static void main(String[] args) {
//如何获取线程的名称
System.out.println(Thread.currentThread().getName());
//两种设置线程名称的方式
Thread t = new Thread(new MyRunnable());
t.setName("wwww");
t.start();
new Thread(new MyRunnable(),"锄禾日当午").start();
//不设置的有默认的名字
new Thread(new MyRunnable()).start();
}
static class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
}
线程休眠sleep
public class Demo4 {
public static void main(String[] args) throws InterruptedException {
//线程的休眠
for (int i = 0; i < 10; i++) {
System.out.println(i);
Thread.sleep(1000); //1000毫秒
}
}
}
线程的中断
public class Demo5 {
public static void main(String[] args) {
//线程中断
//y一个线程是一个独立的执行路径,它是否结束应该由其自身决定
Thread t1 = new Thread(new MyRunnable());
t1.start();
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//给线程t1添加中断标记
t1.interrupt();
}
static class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//e.printStackTrace();
System.out.println("发现了中断标记,线程自杀");
return;
}
}
}
}
}
守护线程
public class Demo6 {
public static void main(String[] args) {
//线程分为守护线程和用户线程
//用户线程:当一个进程不包含任何的存活的用户线程时,进行结束
//守护线程:守护用户线程的,当最后一个用户线程结束时,所有守护线程自动死亡。
Thread t1 = new Thread(new MyRunnable());
//设置守护线程
t1.setDaemon(true);
t1.start();
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
线程不安全问题
public class Demo7 {
public static void main(String[] args) {
//线程不安全
Runnable run = new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable{
//总票数
private int count = 10;
@Override
public void run() {
while (count>0){
//卖票
System.out.println("正在准备卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println("卖票结束,余票:"+count);
}
}
}
}
同步代码块
public class Demo8 {
public static void main(String[] args) {
Object o = new Object();
//线程不安全
//解决方案1 同步代码块
//格式:synchronized(锁对象){
//
//
// }
Runnable run = new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable{
//总票数
private int count = 10;
private Object o = new Object();
@Override
public void run() {
//Object o = new Object(); //这里不是同一把锁,所以锁不住
while (true) {
synchronized (o) {
if (count > 0) {
//卖票
System.out.println("正在准备卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName()+"卖票结束,余票:" + count);
}else {
break;
}
}
}
}
}
}
同步方法
//同步代码块和同步方法都属于隐式锁
//线程同步lock
public class Demo8 {
public static void main(String[] args) {
Object o = new Object();
Runnable run = new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable{
//总票数
private int count = 10;
@Override
public void run() {
while (true) {
synchronized (this) {
//该this和sell同步方法使用的是同一把锁
}
if(!sell()) {
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized boolean sell() {
if (count > 0) {
//卖票
System.out.println("正在准备卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName()+"卖票结束,余票:" + count);
}else {
return false;
}
return true;
}
}
}
显式锁ReentrantLock
//同步代码块和同步方法都属于隐式锁
//线程同步lock
public class Demo10 {
public static void main(String[] args) {
Object o = new Object();
//线程不安全
//解决方案1 显示锁 Lock 子类 ReentrantLock
Runnable run = new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable{
//总票数
private int count = 10;
//参数为true表示公平锁 默认是false 不是公平锁
private Lock l = new ReentrantLock(true);
@Override
public void run() {
while (true) {
l.lock();
if (count > 0) {
//卖票
System.out.println("正在准备卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName()+"卖票结束,余票:" + count);
}else {
break;
}
l.unlock();
}
}
}
}
公平锁与非公平锁
- 公平锁:排队,先来的先获得锁
- 非公平锁:竞争,无顺序
- 实现:
private Lock l = new ReentrantLock(true);
死锁
public class Demo11 {
public static void main(String[] args) {
//线程死锁
Culprit c = new Culprit();
Police p = new Police();
new MyThread(c,p).start();
c.say(p);
}
static class MyThread extends Thread{
private Culprit c;
private Police p;
MyThread(Culprit c,Police p){
this.c = c;
this.p = p;
}
@Override
public void run() {
p.say(c);
}
}
static class Culprit{
public synchronized void say(Police p){
System.out.println("罪犯:你放了我,我放了人质");
p.fun();
}
public synchronized void fun(){
System.out.println("罪犯被放了,罪犯也放了人质");
}
}
static class Police{
public synchronized void say(Culprit c){
System.out.println("警察:你放了人质,我放了你");
c.fun();
}
public synchronized void fun(){
System.out.println("警察救了人质,但是罪犯跑了");
}
}
}
多线程生产者与消费者
public class Demo12 {
public static void main(String[] args) {
//多线程通信 生产者与消费者问题
Food f = new Food();
new Cook(f).start();
new Waiter(f).start();
}
//厨师
static class Cook extends Thread{
private Food f;
public Cook(Food f) {
this.f = f;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if(i%2==0){
f.setNameAndTaste("老干妈小米粥","香辣味");
}else {
f.setNameAndTaste("煎饼果子","甜辣味");
}
}
}
}
//服务员
static class Waiter extends Thread{
private Food f;
public Waiter(Food f) {
this.f = f;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
f.get();
}
}
}
//食物
static class Food{
private String name;
private String taste;
//true表示可以生产
boolean flag = true;
public synchronized void setNameAndTaste(String name,String taste){
if(flag){
this.name = name;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.taste = taste;
flag = false;
this.notifyAll();
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void get(){
if(!flag){
System.out.println("服务员端走的菜的名称是:"+name+",味道是:"+taste);
flag = true;
this.notifyAll();
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
线程的六种状态
带返回值的线程Callable
* java中的第三种线程实现方式
public class CallableDemo {
public static void main(String[] args) throws InterruptedException, ExecutionException {
Callable<Integer> callable = new MyCallable();
FutureTask<Integer> futureTask = new FutureTask<>(callable);
new Thread(futureTask).start();
int j = futureTask.get();
System.out.println("isdone:"+futureTask.isDone());//已经完毕
System.out.println("cancel"+futureTask.cancel(true));//取消
System.out.println("返回值为"+j);
for(int i = 0; i < 10; i++) {
Thread.sleep(100);
System.out.println(i);
}
}
static class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
for(int i = 0; i < 10; i++) {
Thread.sleep(100);
System.out.println(i);
}
return 100;
}
}
}
缓存线程池
public class Demo13 {
public static void main(String[] args) {
//线程池
//创建线程
//创建任务
//执行任务
//关闭线程
//缓存线程池
//无限制长度
//任务加入后的执行流程
//1判断线程池是否存在空闲线程 2存在则使用 3不存在则创建线程并使用
//向线程池中加入新的任务
ExecutorService service = Executors.newCachedThreadPool();
//指挥线程池执行新的任务
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"锄禾日当午");
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"锄禾日当午");
}
});service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"锄禾日当午");
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
定长线程池
public class Demo14 {
/*定长线程池
长度是指定的线程池
加入任务后的执行流程
1 判断线程池是否存在空闲线程
2 存在则使用
3 不存在空闲线程 且线程池未满的情况下 则创建线程 并放入线程池中 然后使用
4 不存在空闲线程 且线程池已满的情况下 则等待线程池的空闲线程
**/
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(2);
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"锄禾日当午");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"锄禾日当午");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"锄禾日当午");
}
});
}
}
单线程线程池
public class Demo15 {
/*单线程线程池
执行流程
1 判断线程池的那个线程是否空闲
2 空闲则使用
3 不空闲则等待它空闲后再使用
**/
public static void main(String[] args) {
ExecutorService service = Executors.newSingleThreadExecutor();
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"锄禾日当午");
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"锄禾日当午");
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"锄禾日当午");
}
});
}
}
周期定长线程池
public class Demo16 {
/*周期任务 定长线程池
执行流程
1 判断线程池是否存在空闲线程
2 存在则使用
3 不存在空闲线程 且线程池未满的情况下 则创建线程 并放入线程池中 然后使用
4 不存在空闲线程 且线程池已满的情况下 则等待线程池的空闲线程
周期性任务执行时
定时执行 当某个任务触发时 自动执行某任务
**/
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
//定时执行一次
//参数1:定时执行的任务
//参数2:时长数字
//参数3:2的时间单位 Timeunit的常量指定
/* scheduledExecutorService.schedule(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"锄禾日当午");
}
},5, TimeUnit.SECONDS); //5秒钟后执行*/
/*
周期性执行任务
参数1:任务
参数2:延迟时长数字(第一次在执行上面时间以后)
参数3:周期时长数字(没隔多久执行一次)
参数4:时长数字的单位
* **/
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"锄禾日当午");
}
},5,1,TimeUnit.SECONDS);
}
}
Lambda表达式
public class Demo17 {
/*
lambda表达式
函数式编程思想
**/
public static void main(String[] args) {
//冗余的Runnable编写方式
/* Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("锄禾日当午");
}
});
t.start();*/
Thread t = new Thread(() -> System.out.println("锄禾日当午"));
t.start();
/*print(new MyMath() {
@Override
public int sum(int x, int y) {
return x+y;
}
}, 100, 200);*/
print((int x, int y) -> {
return x+y;
}, 100, 200);
}
public static void print(MyMath myMath, int x, int y){
int sum = myMath.sum(x, y);
System.out.println(sum);
}
public interface MyMath {
int sum(int x, int y);
}
}