Java高并发 二 [多线程基础]

Java高并发 二 [多线程基础]

1 进程和线程

进程是操作系统分配资源的最小单元,线程是操作系统调度的最小单元。
进程:就是一个应用程序在处理机上的一次执行过程,它是一个动态的概念。进程是一个“执行中的程序”,通常在一个进程中可以包含若干个线程,它们可以利用进程所拥有的资源。
线程:线程是进程内的执行单元。使用线程的原因是,进程的切换是非常重量级的操作,非常消耗资源。如果使用多进程,那么并发数相对来说不会很高。而线程是更细小的调度单元,更加轻量级,所以线程会较为广泛的用于并发设计。

2 线程的基本操作

2.1 线程状态图

线程状态图
新建状态(NEW):新建一个线程对象。
就绪状态(RUNNABLE):线程对象创建后,调用了其start()方法,该状态的线程既可有机会获取CUP的使用权。
运行状态(RUNNING):就绪状态的线程获取了CPU,执行对象的run()方法。
阻塞状态(BLOCKED):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
1、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
2、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
3、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
ps:调用sleep()方法不会释放锁。

2.2 新建线程

第一种方式

Thread t = new Thread();    //继承thread类,重写run()方法
t.start();  //执行t中的run()方法

第二种方式(推荐用这种方法,可以实现多个接口)

Thread t = new Thread(new Runnalbe1()); //Runnalbe1实现Runnable接口,重写run()方法
t.start();  //执行t中的run()方法
2.3 线程中断

线程中断有3种方法

public void Thread.interrupt() // 中断线程 
public boolean Thread.isInterrupted() // 判断是否被中断 
public static boolean Thread.interrupted() // 判断是否被中断,并清除当前中断状态

调用线程对象的interrupt方法并不一定会中断正在运行的线程,它只是一种机制,要求线程在合适的时机中断自己。每个线程都有一个boolean的中断属性,而interrupt只是将这个属性置为true,对于非阻塞的线程,只是改变了这个属性,并不会试线程停止。

public void run(){//线程t
   while(true){
      Thread.yield();
   }
}
t.interrupt();//这样子不会使线程中断
public void run(){ //线程t
    while(true)
    { 
        if(Thread.currentThread().isInterrupted())
        { 
           System.out.println("Interruted!"); 
           break; 
        } 
        Thread.yield(); 
    } 
}
t.interrupt();//这样子才能使线程中断
2.4 线程等待
2.4.1、休眠sleep()

调用线程的sleep方法,会让运行中的线程休眠指定的时间,休眠结束后可回到就绪状态,并不一定会立即获得运行状态。sleep是Thread类的静态方法,sleep方法不会释放锁,休眠时其他线程无法访问同个对象。

2.4.2、等待wait()

调用线程的wait方法,也会让运行中的线程等待执行的时间,这个线程进入一个和该对象相关的等待池中。wait是由Object类提供的,wait方法会释放锁,其他线程可以访问。
wait需要notify或者notifyAll或者等待时间来唤醒当前线程池中的线程。

2.4.3、join和yeild

yeild:线程让步,将当前线程从运行状态变为就绪状态,还是有机会再次获得cpu使用权的。
join:当前线程等待调用join方法的线程结束,如果调用线程没结束,当前线程一直处于阻塞。
join的本质:

while(isAlive()) 
{ 
   wait(0); 
}
2.5 基本的线程同步操作

synchronized有三种加锁方式。
1、指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。

public class A{
    private int i;
    public void test(){
        synchronized(this){
         System.out.println(Thread.currentThread().getName() + "---" + i++);
            try {
                Thread.sleep(500);
            }catch (InterruptedException e){

            }
        }
    }
}

final A a = new A();
final A b = new A();
Thread ta = new Thread(new Runnable(){
    @Override
    public void run(){
        for (int i = 0; i< 3 ; i ++){
            a.test();
        }
    }
});
Thread tb = new Thread(new Runnable(){
    @Override
    public void run(){
        for (int i = 0; i< 3 ; i ++){
            b.test();
        }
    }
});
ta.start();
tb.start();
结果:同步锁的是传入的对象,这里可以发现不会发生锁竞争。
Thread-0---0
Thread-1---0
Thread-0---1
Thread-1---1
Thread-0---2
Thread-1---2

2、直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。

public class A{
    private int i;
    //作用于实例方法
    public synchronized void test(){
        System.out.println(Thread.currentThread().getName() + "---" + i++);
            try {
                Thread.sleep(500);
            }catch (InterruptedException e){

            }
        }
    }
}

final A a = new A();
final A b = new A();
Thread ta = new Thread(new Runnable(){
    @Override
    public void run(){
        for (int i = 0; i< 3 ; i ++){
            a.test();
        }
    }
});
Thread tb = new Thread(new Runnable(){
    @Override
    public void run(){
        for (int i = 0; i< 3 ; i ++){
            b.test();
        }
    }
});
ta.start();
tb.start();
结果:同步锁的是实例对象,这里可以发现不会发生锁竞争,因为是不同的实例对象。
Thread-0---0
Thread-1---0
Thread-0---1
Thread-1---1
Thread-0---2
Thread-1---2

3、直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。

public class A{
    private static int i;
    //作用于静态方法
    public static synchronized void test(){
        System.out.println(Thread.currentThread().getName() + "---" + i++);
            try {
                Thread.sleep(500);
            }catch (InterruptedException e){

            }
        }
    }
}

final A a = new A();
final A b = new A();
Thread ta = new Thread(new Runnable(){
    @Override
    public void run(){
        for (int i = 0; i< 3 ; i ++){
            a.test();
        }
    }
});
Thread tb = new Thread(new Runnable(){
    @Override
    public void run(){
        for (int i = 0; i< 3 ; i ++){
            b.test();
        }
    }
});
ta.start();
tb.start();
结果:同步锁的是当前类,这里可以发现会发生锁竞争,因为是同一个类。
Thread-0---0
Thread-0---1
Thread-0---2
Thread-1---3
Thread-1---4
Thread-1---5

Reference:
1. https://my.oschina.net/hosee/blog/599000

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值