Java_04 多线程:Thread,Runnable,Callable,Lambda
多线程
Process进程:是程序的一次执行过程,是系统运行程序的基本单位,一个进程就是一个执行中的程序;
Thread线程(main,gc):与进程类似,是一个比进程更小的执行单位,一个进程中可以执行多个线程,多个线程可以共享同一块空间
线程创建:继承Thread类,实现Runable接口,实现Callable接口
继承Thread类
package com.alpari;
/**
* 创建线程方式一:继承Thread类,重写run()方法,调用start()方法开启线程
* 线程开启不一定执行,由CPU调度执行
*/
public class DemoThread extends Thread{
@Override
public void run() {
// run方法线程体
for (int i = 0; i < 5; i++) {
System.out.println("----"+i);
}
}
public static void main(String[] args) {
// 创建一个线程对象
DemoThread thread = new DemoThread();
// 调用start()方法开启线程
thread.start();
System.out.println("-------");
}
}
实现Runnable接口
package com.alpari;
/**
* 创建线程方式二:实现runnable接口,重写run()方法,调用start()方法开启线程
* 线程开启不一定执行,由CPU调度执行,避免单继承局限。
*/
public class DemoThread implements Runnable{
@Override
public void run() {
// run方法线程体
for (int i = 0; i < 5; i++) {
System.out.println("----"+i);
}
}
public static void main(String[] args) {
// 创建一个线程对象
DemoThread thread = new DemoThread();
// 创建线程对象,通过线程对象来开启多线程(代理)
new Thread(thread).start();
}
}
package com.alpari;
/**
* 抢票问题:
* 发现问题:多个线程操作同一个资源的情况下,线程不安全
*/
public class DemoThread implements Runnable{
private int ticketNum = 10;
@Override
public void run() {
// run方法线程体
while (true) {
if (ticketNum <= 0){
break;
}
// 模拟延时
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"--"+ ticketNum--);
}
}
public static void main(String[] args) {
// 创建一个线程对象
DemoThread thread = new DemoThread();
// 创建线程对象,通过线程对象来开启多线程(代理)
new Thread(thread, "q").start();
new Thread(thread, "w").start();
new Thread(thread, "e").start();
}
}
// 输出:
e--10
w--10
q--10
e--9
q--8
w--9
e--7
q--5
w--6
e--4
w--4
q--3
w--2
e--2
q--2
w--1
e--0
q--1
实现Callable接口
package com.alpari;
import java.util.concurrent.*;
/**
* 创建方式三:实现Callable接口,有返回值
*/
public class DemoThread implements Callable<String> {
@Override
public String call() throws Exception {
int num = 10;
for (int i = 0; i < 10; i++) {
if (i>0) {
System.out.println("卖票:"+num--);
}
}
return "今日票已卖光";
}
public static void main(String[] args) throws Exception {
// 创建一个线程对象
DemoThread thread = new DemoThread();
// 创建执行服务,创建一个线程池 Executors.newFixedThreadPool(1)
ExecutorService ex = Executors.newFixedThreadPool(1);// 1 代表线程数量
// 提交执行
Future<String> submit = ex.submit(thread);
// 获取结果
String s = submit.get();
System.out.println(s);
// 关闭服务
ex.shutdown();
}
}
Lamda表达式
任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口(JDK1.8);对于函数式接口,我们可以通过lambda表达式来创建该接口的对象
package com.alpari;
public class DemoLambda {
// 3.静态内部类
static class Like implements ILike{
@Override
public void lambda() {
System.out.println("I like lambda2");
}
}
public static void main(String[] args) {
ILike like = new ILikeImpl();
like.lambda();
Like like2 = new Like();
like2.lambda();
// 3.匿名内部类
new ILike() {
@Override
public void lambda() {
System.out.println("I like lambda3");
}
}.lambda();
// 4.lambda表达式
like = () -> {
System.out.println("I like lambda4");
};
like.lambda();
}
}
// 1.定义一个函数式接口
interface ILike {
void lambda();
}
// 2.实现类
class ILikeImpl implements ILike {
@Override
public void lambda() {
System.out.println("I like lambda");
}
}
线程状态
停止线程
package com.alpari;
/**
* 建议线程正常停止:利用次数,不建议死循环
* 建议使用标志位:设置一个标志位
* 不要使用stop,destory等过时方法
*/
public class DemoStop implements Runnable{
// 1.设置一个标识位
private boolean flag = true;
@Override
public void run() {
int i = 0;
while (flag) {
System.out.println("run...thread"+i);
}
}
// 2.设置一个方法
public void stop() {
this.flag = false;
}
public static void main(String[] args) {
DemoStop stop = new DemoStop();
new Thread(stop).start();
for (int i = 0; i < 100; i++) {
System.out.println("main"+i);
if (i == 80) {
// 调用stop方法切换标志位,让线程停止
stop.stop();
System.out.println("线程该停止了。。");
}
}
}
}
// 输出:
...
main79
main80
run...thread0
线程该停止了。。
main81
main82
...
线程休眠 sleep
package com.alpari;
import java.text.SimpleDateFormat;
import java.util.Date;
// 模拟倒计时
public class DemoSleep {
public static void a() {
int num = 10;
while (true) {
try {
Thread.sleep(1000);
System.out.println(num--);
if (num<=0) {
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
// a(); // 调用倒计时方法
// 打印当前时间
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();
}
}
}
}
// 输出:
16:39:31
16:39:32
16:39:33
线程安全问题
package com.alpari;
// 模拟买票
public class UnSafeBuyTicket {
public static void main(String[] args) {
BuyTicket buyTicket = new BuyTicket();
new Thread(buyTicket, "a").start();
new Thread(buyTicket, "b").start();
}
}
class BuyTicket implements Runnable {
// 票
private int ticketNum = 10;
boolean flag = true; // 外部停止方式
@Override
public void run() {
// 买票
while (flag) {
try {
buy();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// public synchronized void buy() 利用synchronized来保证安全,可以锁方法也可以锁个代码块,默认锁的是this当前对象,哪个是变化的就锁哪个就行了。
public void buy() throws InterruptedException {
// 判断是否有票
if (ticketNum<=0) {
flag = false;
return;
}
// 模拟延时
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"拿到"+ticketNum--);
}
}
// a和b都拿到6
b拿到10
a拿到9
a拿到8
b拿到7
b拿到6
a拿到6
优先级Priority
public class MainClass2 {
public static void main(String[] args) {
System.out.println(Thread.currentThread());
MyThread my= new MyThread();
//通过Thread类的构造方法给线程起名,线程默认名为Thread-N
Thread t1 = new Thread(my,"线程A");
Thread t2 = new Thread(my,"线程B");
Thread t3 = new Thread(my,"线程C");
//改变线程的优先级,最大为10,最小为1,当线程的优先级较大时,抢占资源的可能性会较大,线程默认优先级是5
t1.setPriority(Thread.MIN_PRIORITY);
t2.setPriority(Thread.MAX_PRIORITY);
t1.start();
t2.start();
t3.start();
}
}
问题
- sleep和wait的区别:
- sleep是Thread类的方法,wait是Object类的方法
- sleep方法不能被唤醒,wait可以被notify和notifyAll唤醒
- sleep不会释放当前对象的资源锁,wait会释放
- notify和notifyAll的区别:
- notify是哪个线程先睡眠,则先唤醒哪个,排队唤醒
- notifyAll是一起唤醒所有,谁先抢到资源谁先执行
- 线程的声明周期:
- 新建--就绪--运行--阻塞--死亡
- 生产者消费者模式。。。。。