多线程
进程:进程是资源分配的最小单位,运行的程序就是进程:qq.exe
线程:线程是程序执行的最小单位,也就是cpu调度执行的最小单位,程序中含有多个线程:聊天,视频
真正的多线程应该是多核cpu,单核cpu其实只是在线程间连续切换
多核cpu才可以做到并行
线程的创建(四种方式)
第一种 继承Thread类
package com.itheima.my;
import java.util.concurrent.TimeUnit;
//继承Thread类 重写 run 方法 调用start开启线程
//线程开启不一定立即执行 由cpu来调度
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
TimeUnit.MILLISECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread" + i);
}
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
for (int i = 0; i < 20; i++) {
try {
TimeUnit.MILLISECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main" + i);
}
}
}
第二种 实现Runnable接口
/*
创建多线程程序的第二种方式:实现Runnable接口
java.lang.Runnable
Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为 run 的无参数方法。
java.lang.Thread类的构造方法
Thread(Runnable target) 分配新的 Thread 对象。
Thread(Runnable target, String name) 分配新的 Thread 对象。
实现步骤:
1.创建一个Runnable接口的实现类
2.在实现类中重写Runnable接口的run方法,设置线程任务
3.创建一个Runnable接口的实现类对象
4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象
5.调用Thread类中的start方法,开启新的线程执行run方法
实现Runnable接口创建多线程程序的好处:
1.避免了单继承的局限性
一个类只能继承一个类(一个人只能有一个亲爹),类继承了Thread类就不能继承其他的类
实现了Runnable接口,还可以继承其他的类,实现其他的接口
2.增强了程序的扩展性,降低了程序的耦合性(解耦)
实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离(解耦)
实现类中,重写了run方法:用来设置线程任务
创建Thread类对象,调用start方法:用来开启新线程
*/
public class Demo01Runnable {
public static void main(String[] args) {
//3.创建一个Runnable接口的实现类对象
RunnableImpl run = new RunnableImpl();
//4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象
Thread t = new Thread(run);//打印线程名称
//5.调用Thread类中的start方法,开启新的线程执行run方法
t.start();
for (int i = 0; i <20 ; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
}
//1.创建一个Runnable接口的实现类
public class RunnableImpl implements Runnable{
//2.在实现类中重写Runnable接口的run方法,设置线程任务
@Override
public void run() {
for (int i = 0; i <20 ; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
}
//龟兔赛跑
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(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
boolean b = gameOver(i);
if (b){
break;
}
System.out.println(Thread.currentThread().getName()+"跑了"+i+"步数");
}
}
private boolean gameOver(int step){
if (winner!=null) {
return true;
}{
if (step>=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接口
import java.util.concurrent.Callable;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
/**
* 不用lambda表达式,就是这样,先创建一个callable的实现类。
* @author LENOVO
*/
public class CallableTest implements Callable<Integer>{
/**重写执行体call()*/
@Override
public Integer call() throws Exception {
int i = 0;
int target = 10;
for(;i<target;i++){
try { TimeUnit.MILLISECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
//当前线程
System.out.println("当前线程是:::"+Thread.currentThread()
+":"+i);
}
return i;
}
public static void main(String[] args) {
//创建callable对象
CallableTest call=new CallableTest();
FutureTask<Integer> fu=new FutureTask<Integer>(call);
Thread th=new Thread(fu,"我是fu线程");
th.start();
for (int i = 0; i < 30; i++) {
try { TimeUnit.MILLISECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
//当前线程
System.out.println(Thread.currentThread().getName()+"当前线程");
}
}
}
第四种 使用线程池创建
使用线程池来创建线程的相关问题
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPool {
public static void main(String[] args) {
ExecutorService executorService = new ThreadPoolExecutor(5, 10, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(5));
for (int i = 0; i < 10; i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "执行");
}
});
}
executorService.shutdown();
}
}
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.*;
/**
* @author name
* @date 2020/7/22
* 使用guava来创建
*/
public class GuavaThreadPoolDemo {
/**
*为线程池创建的线程命名*/
private static ThreadFactory nameDthreadFactory =
new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build();
private static ExecutorService executorService = new ThreadPoolExecutor(5,5,60, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(10),nameDthreadFactory,new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println("测试一下guava命名的线程"+Thread.currentThread().getName());
}
});
}
executorService.shutdown();
}
}
start方法内部是
底层是在内核创建一个线程,线程模型是1:1
syn锁也是在内核线程上锁,属于重量级锁
并发问题:买票
/*
模拟卖票案例
创建3个线程,同时开启,对共享的票进行出售
*/
//多个线程访问一个资源时,会产生线程安全问题
public class Demo01Ticket {
public static void main(String[] args) {
//创建Runnable接口的实现类对象
RunnableImpl run = new RunnableImpl();
//创建Thread类对象,构造方法中传递Runnable接口的实现类对象
Thread t0 = new Thread(run);
Thread t1 = new Thread(run);
Thread t2 = new Thread(run);
//调用start方法开启多线程
t0.start();
t1.start();
t2.start();
}
}
/*
实现卖票案例
*/
public class RunnableImpl implements Runnable{
//定义一个多个线程共享的票源
private int ticket = 100;
//设置线程任务:卖票
@Override
public void run() {
//使用死循环,让卖票操作重复执行
while(true){
//先判断票是否存在
if(ticket>0){
//提高安全问题出现的概率,让程序睡眠
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//票存在,卖票 ticket--
System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
ticket--;
}
}
}
}