多线程
JAVA(多线程)
创建线程
1.继承Thread类,重写run方法
Thread不是抽象类,run方法不是抽象方法
MyThread继承了Thread类之后,他就是一个独立的线程
要让线程启动,调用start方法
package duoxiancheng;
class MyThread extends Thread{
@Override
public void run(){
System.out.println("线程启动");
}
}
public class Test1 {
public static void main(String[] args) {
MyThread myThread=new MyThread();
//当调用start方法启动一个线程时,会执行重写的run方法的代码
myThread.start();//启动线程
}
}
2.实现Runnable接口
package duoxiancheng;
class MyThread2 implements Runnable{
@Override
public void run(){
System.out.println("实现Runnable");
}
}
public class Test2 {
public static void main(String[] args) {
//想要线程启动,需要调用Thread类中的start
MyThread2 myThread2=new MyThread2();
Thread t=new Thread(myThread2);
t.start();
}
}
使用箭头函数
/**
* 使用箭头函数(lambda表达式)
*/
public class JianTouHanShu {
public static void main(String[] args) {
//箭头函数接口,抽象类,重写方法
new Thread(
() -> System.out.println(2)
).start();
}
}
3.实现Callable接口
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
class MyThread3 implements Callable<String>{
@Override
public String call() throws Exception {
return null;
}
}
public class Test3 {
public static void main(String[] args) {
FutureTask<String> futureTask=new FutureTask<>(new MyThread3());
new Thread(futureTask).start();
}
}
线程的优先级
概率,比如90%跑主方法,10%跑myThread
继承Thread类和实现Runnable接口、实现Callable接口的区别。
继承Thread:线程代码存放在Thread子类run方法中。
优势:编写简单,可直接用this.getname()获取当前线程,不必使用Thread.currentThread()方法。
劣势:已经继承了Thread类,无法再继承其他类。
实现Runnable:线程代码存放在接口的子类的run方法中。
优势:避免了单继承的局限性、多个线程可以共享一个target对象,非常适合多线程处理同一份资源的情形。
劣势:比较复杂、访问线程必须使用Thread.currentThread()方法、无返回值。
实现Callable:
优势:有返回值、避免了单继承的局限性、多个线程可以共享一个target对象,非常适合多线程处理同一份资源的情形。
劣势:比较复杂、访问线程必须使用Thread.currentThread()方法
Java提供两种线程
用户线程
守护线程:为用户线程提供服务
Thread t = new Thread();
t.setDaemon(true);
线程的生命周期
1.NEW 线程未被Start()调用执行
2.RUNNABLE,线程正在JVM中被执行,等待来自操作系统的调度
3.BLOCKED,阻塞,不能立即执行,需要挂起等待
4.WAITING,无限期等待,Object类,没有唤醒,一直等待
5.TIMED_WAITING,线程等待一个指定的时间
6.TERMINATED,中止线程的状态
等待和阻塞:阻塞因为外部原因,需要等待
线程状态管理
1、线程睡眠---sleep:
线程睡眠的原因:线程执行的太快,或需要强制执行到下一个线程。
线程睡眠的方法(两个):sleep(long millis)在指定的毫秒数内让正在执行的线程休眠。
sleep(long millis,int nanos)在指定的毫秒数加指定的纳秒数内让正在执行的线程休眠。
2、线程让步---yield:
Thread类提供的一个静态方法,可以让正在执行的线程暂停,但是不会进入阻塞状态,而是直接进入就绪状态。相当于只是将当前线程暂停一下,然后重新进入就绪的线程池中,让线程调度器重新调度一次。也会出现某个线程调用yield方法后暂停,但之后调度器又将其调度出来重新进入到运行状态。
3、线程合并---join:
当B线程执行到了A线程的.join()方法时,B线程就会等待,等A线程都执行完毕,B线程才会执行。
4、停止线程:
开启多线程运行,运行的代码通常是循环结构,只要控制住循环,就可以让run方法结束。
5、设置优先级:
Thread类中提供了优先级的三个常量
MAX_PRIORITY = 10
MIN_PRIORITY = 1
NORM_PRIORITY = 5
------------------------------------------------------
ThreadDemo td = new ThreadDemo();
Thread t1 = new Thread(td,"设置");
t1.priority(9);
//设置优先级
t1.start();
//设置完毕
线程安全
CPU多核缓存结构
物理内存:硬盘内存
cpu缓存为了提高程序运行的性能,
cpu处理速度最快,内存次之,硬盘最后
cpu处理数据时,内存运行速度慢,会拖累cpu的速度
解决这样的问题,cpu有多级缓存(三级缓存)每个cpu都有L1,L2缓存,L3缓存多核公用
CPU查找数据:CPI->L1->L2->L3->内存->硬盘
线程安全的实现
数据不可变
互斥同步,加锁(悲观锁)
非阻塞同步(无锁编程)自旋,用cas实现
无同步方案,多个线程需要共享数据,但这些数据可以在单独的线程中计算
线程同步与锁
线程同步:java允许多线程并发控制,当多个线程同时操作一个可共享资源变量时(如对其进行增删改查操作),会导致数据不准确,而且相互之间产生冲突。所以加入同步锁以避免该线程在没有完成操作前被其他线程调用,从而保证该变量的唯一性和准确性。
方法一
同步函数:就是用synchronize关键字修饰的方法。因为每个java对象都有一个内置锁,当用synchronize关键字修饰方法时内置锁会保护整个方法,而在调用该方法之前,要先获得内置锁,否则就会处于阻塞状态。
public synchronized void run() {}
方法二
同步代码块:就是拥有synchronize关键字修饰的语句块,被该关键字修饰的语句块会自动被加上内置锁,从而实现同步。
public void run() {
while(true){
synchronized (this) { //同步代码块
if(tick>0){
try {
Thread.sleep(10);//执行中让线程睡眠10毫秒,
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " " + tick--);
}
}
}
}
方法三
lock锁
案例:
package duoxiancheng;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class MyThread_3 implements Runnable{
private Integer sum=50;
@Override
public synchronized void run() {//synchronized关键字
while(true){
if(sum==0){
break;
}
System.out.println(sum);
sum = sum - 1;
}
}
}
class MyThread_4 implements Runnable{
private Integer sum=50;
@Override
public void run() {
while(true){
synchronized (this) { //同步代码块
if(sum>0){
try {
Thread.sleep(10);//执行中让线程睡眠10毫秒,
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " " + sum--);
}
}
}
}
}
class MyThread_5 implements Runnable{
private Lock lock=new ReentrantLock();
private Integer sum=50;
@Override
public void run() {
lock.lock();//lock锁
try {
while(true){
if(sum==0){
break;
}
System.out.println(sum);
sum = sum - 1;
}
} finally {
lock.unlock();
}
}
}
public class Test9 {
public static void main(String[] args) {
//synchronized关键字
MyThread_3 t1=new MyThread_3();
Thread t11=new Thread(t1);
Thread t22=new Thread(t1);
Thread t33=new Thread(t1);
t11.start();
t22.start();
t33.start();
// //同步代码块
MyThread_4 t11s=new MyThread_4();
Thread t111=new Thread(t11s);
Thread t221=new Thread(t11s);
Thread t331=new Thread(t11s);
t111.start();
t221.start();
t331.start();
//lock锁
MyThread_5 tt1=new MyThread_5();
Thread tr1=new Thread(tt1);
Thread tr2=new Thread(tt1);
Thread tr3=new Thread(tt1);
tr1.start();
tr2.start();
tr3.start();
}
}
线程执行完再执行别的
strictfp
死锁
进程A中包含资源A,进程B中包含资源B,A的下一步需要资源B,B的下一步需要资源A,所以它们就互相等待对方占有的资源释放,所以也就产生了一个循环等待死锁。

浙公网安备 33010602011771号