多线程--java

多线程

单核cpu没有并行,它只不过是CPU时钟调度给你错觉,让你误以为他们真的在同一时间同时运行。

多核cpu才有并行

每一个task就是一个进程(Process), 在每一个process中至少有一个线程(Thread)在运行, 有时线程也称为轻量级的进程

每个thread , 都有自己的局部变量表,程序计数器以及各自的生命周期

java每创建一个Thread就创建一个线程,java创建的线程默认是处于非阻塞状态,异步通信机制,以及线程内存共享

下面是一个简单的并行,sayhi(),sayno()为两个静态方法,下面有两个线程,一个lambada表达式,一个是main

 

 syano也是如此,添加sleep(100)的原因是 10个for循环可能就是一毫米的事情

    private static  void sayhi(){
        for(int i=0;i<10;i++){
            System.out.println("hi");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
   }

 

 

阻塞非阻塞是程序等待调用结果的状态

阻塞调用: 没立即得到结果,当前线程会被挂起 ,也就是处于阻塞状态

非阻塞调用:没立即得到结果,不会阻塞当前线程

同步异步是消息通信机制

同步: 等阻塞调用得到返回结果后,才返回I/O系统

异步:因为不阻塞当前线程,立即返回I/O系统,CPU可以去处理其它线程,等收到返回结果后,再去处理该线程

默认都是非阻塞调用,异步通信机制,因为它可以大大提高CPU性能。

为了更高效地减小线程的开销,多个线程可以对同一个内存资源共享调用,但会造成线程不安全

线程不安全:(多线程和单线程运行的结果不一样)

解释: 多线程调用与单线程(加锁)调用相同内存资源的结果不一样

 线程安全:(每次运行的结果和单线程运行的结果是不一样的,而且其他的变量的值也和预期的是一样的)

加锁,通过加synchronized ,使某程序不能内存共享,阻塞调用,异步通信机制,所以对相同内存只能单线程运行。

注意:对不同内存资源是多线程。

也就是说加锁只对于线程访问相同内存资源,对于访问不同的内存资源不影响

 

对线程访问同一个内存资源代码不加锁

 

对线程访问同一内存资源加锁

 

 

对同一内存资源可以是 方法,代码块,对象

synchronized 修饰方法

如上图所示

synchronized 修饰代码块

synchronized(this){
    //**代码块**//
}

 synchronized 修饰对象

synchronized(MultiThreading.class){
    
}
synchronized(对象名){

}

 

线程的五种状态

创建状态 NEW

创建了线程对象,已经有相应的内存空间,但处于不可运行状态。 例如:Thread thread=new Thread()

 就绪状态 RUNNABLE

启动了线程,也就是 start(),已经在JVM中创建了线程,但是还在等待CPU的调度 (线程的运行都听从于CPU的调度)

 运行状态 RUNNING

线程获得CPU的执行,注意线程只能从runnable 到 running
在该状态中,可以发生如下转换:
  - 直接进入TERMINATED状态, 比如已经弃用的stop(),判断中断标识来判断是否中断线程interrupt()
  - 进入BOLOCKED状态,比如调用了sleep, wait方法,进行某个阻塞的IO操作,获得某个锁资源
  - 进入RUNNABLE状态, 比如由于CPU的调度器轮询使该线程放弃执行, 线程主动调用yield方法,放弃CPU执行权

 阻塞状态  BOLOCKED

该线程处于阻塞状态。sleep() , suspend(), wait()等会使线程进入阻塞状态,直到过了sleep()时间,调用resume(),调用notify()等
在该状态下可切换至如下几个状态:
  - 直接进入TERMINATED状态
  - 线程阻塞状态结束,比如过了sleep()时间,notify/notifyall唤醒等进入RUNNABLE状态

 TERMINATED

一个线程的最终状态

 

suspend() 与 resume()  暂停与暂停后继续

run()中加入suspend(),程序运行到suspend()后,线程中断,进入阻塞状态,等到线程对象调用sleep()与resume()后,线程继续
suspend()不会释放所持锁,如果resume()在suspend()之前,会造成死锁,已弃用

//i==3时会停一秒钟,再输出3,4,5
//如果注释掉resume(),程序将输出1,2 然后一直处于等待状态
public class MultiThreading implements Runnable{ @Override public synchronized void run() { for (int i = 1; i <= 5; i++) { if (i ==3) { Thread.currentThread().suspend(); } System.out.println(String.format("i:%s 线程:%s", i, Thread.currentThread().getName())); } } public static void main(String args[]) throws InterruptedException { MultiThreading a = new MultiThreading(); Thread one = new Thread(a); one.start();       Thread.sleep(1000);     one.resume(); } }

 wite() 与 notify()


wait() 与 notify() 必须要在相同对象锁下调用(在synchronized(){}内调用),不然会抛出java.lang.IllegalMonitorStateException的异常


synchronized(this) 指当前对象, synchronized(对象) 指该对象锁


wait()与notify()是Object对象就有的,也就是说所有对象都有


调用wait() 会释放该锁,该线程进入阻塞,但是其它线程可以接管该锁; 不同于suspend() ,suspend()不会释放锁,线程会一直挂在那并且其它线程无法继续访问与它的相同内存资源,直到等到resume();


wait()相比于suspend()不会造成死锁


join()
等待该线程完成后,才能继续运行join()之后的程序

加锁下输出1~10

public class MultiThreading implements Runnable{
    public synchronized void run() {    
    	int i=1;
    	while(i<10) {
    		i++;
    	}
    }

    public static void main(String[] args) {
    	MultiThreading a = new MultiThreading();
    	Thread threadOne = new Thread(a);
    	Thread threadTwo = new Thread(a);
        threadOne.start();
        threadTwo.start();
    }
}

 结果是1 2 3 4 5 6 7 8 9  1 2 3 4 5 6 7 8 9

它只能先执行完threadOne ,然后再执行threadtwo

 

加锁并加wait()与notify() 使输出结果为 112233445566778899

public class MultiThreading implements Runnable{
    public synchronized void run() {    
    	int i=1;
    	while(i<10) {
    		this.notifyAll();
    		try {
			this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    		System.out.println(i);
    		i++;
    	}
    	this.notifyAll();
    }

    public static void main(String[] args) {
    	MultiThreading a = new MultiThreading();
    	Thread threadOne = new Thread(a);
    	Thread threadTwo = new Thread(a);
        threadOne.start();
        threadTwo.start();
    }
}

 

通过往实现的Runnable接口的类 加入对象锁 Object lock ,

实现多个线程的调度

如下是输出 1212121212121212

public class MultiThreading implements Runnable{
	private int num;
	private Object lock;
	public MultiThreading(int num,Object lock) {
		this.num = num;
		this.lock=lock;
	}
    public  void run() {    
    	synchronized(lock) {
	    	int i=1;
	    	while(i<10) {
	    		lock.notifyAll();
	    		try {
				lock.wait();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	    		System.out.println(num);
	    		i++;
	    	}
	    	lock.notifyAll();
    	}
    }

    public static void main(String[] args) {
    	Object lock =new Object();
    	MultiThreading a_one = new MultiThreading(1,lock);
    	MultiThreading a_two = new MultiThreading(2,lock);

    	Thread threadOne = new Thread(a_one);
    	Thread threadTwo = new Thread(a_two);
        threadOne.start();
        threadTwo.start();
    }
}

 不加wait()与notify()的结果是  先执行完线程threadOne,后执行threadTwo

 

posted @ 2021-11-28 11:26  binbin_cloud  阅读(60)  评论(0编辑  收藏  举报