Java 并发机制(Java 5 新特性, Thread, 锁)

常见误解情况:

Thread.yield(): 放弃当前的cpu时间片,进入ready to run状态. 

Thread.yield():建议放弃当前cpu时间片,但是否放弃由jvm决定。

 

Java 5新特性:

        ExecutorService exec = Executors.newCachedThreadPool();
        exec.execute( new MyThread1(););
        exec.execute(new MyThread2());
        exec.shutdown();
 
Executors.newCachedThreadPool();
Executors.newFixedThreadPool(5);
Executors.newSingleThreadExecutor();// 等于Executors.newFixedThreadPool(1);

java 不建议直接使用线程,而是添加了executors类,我们使用的时候只需要将需要做的事情放入exec.execute()中,设定执行的线程数,其余的事情由java调度。

 

Executors.newSingleThreadExecutor():一个线程顺序执行放入的任务。

 

execute.submit(Callable )返回Future类,可以异步的查看线程运行状况已经运行结果。

 

Lock lock = new ReentrantLock();

lock.lock();

try{

    code block;

}finally{

    lock.unlock();

}

 可以显式的调用lock实现线程工作。

 

 

锁:

对象锁:每个对象上都有一把锁,但一个线程获得这个对象锁后,其他线程将被阻塞,直到获得对象锁的线程释放该锁。

1. 当synchronized直接修饰方法时,进入该方法的线程获得的是该方法对应实例的对象锁。

2. 当synchronized直接修饰代码块的时候,synchronized(**){code block}, 线程获得的是对象**的锁。

 

类锁:当synchronized修饰静态方法的时候,静态方法获得的是类锁。

1. public static synchronized void instance(){code block}, 调用该方法的线程获得的是该方法从属的类的锁。

 

底层实现: 对象锁计数器初始化为0,当获得对象锁的对象多次获得对象锁的同时,对象锁计数器会累加。当计数器为0的时候,其他线程才能获得对象锁。)

 

多线程协作:

wait()和notify()用来是当前线程挂起或者唤醒。

他们作为Object基类的一部分是因为他们都是操作锁的,锁是所有对象的一部分而非Thread特有。

 

wait()的含义:我已经做完线程该做的事情,且等待其他线程或者资源。所以释放对象锁,等待再次被唤醒。

wait()可以防止线程忙等待。

若wait()的使用没有获得锁则抛出IllegalMonitorStateException

 

 

wait()使用必须获得锁,且notify()使用也必须获得锁,且notify()唤醒的是notify()所获得锁所对应的wait()方法。

class MyThread1 implements Runnable {
    public boolean flag = true;
    Object syncObject = new Object();
    @Override
    public void run() {
        synchronized (syncObject
) {
            System.out.println("Entry thread 1");
            while (flag) {
                System.out.println("thread 1 wait");
                try {
                    syncObject.wait();

                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
            }
            System.out.println("Out of thread 1");
        }
    }
}

class MyThread2 implements Runnable {
    Runnable runnable;
    public MyThread2(Runnable runnable) {
        this.runnable = runnable;
    }
    
    @Override
    public synchronized void run() {
        System.out.println("Entry thread 2");
        
        int i = 0;
        while (((MyThread1)runnable).flag) {
            synchronized (((MyThread1)runnable).syncObject
) {
                i++;
                if (i == 5) {
                    ((MyThread1)runnable).flag = false;
                }
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                ((MyThread1)runnable).syncObject.notifyAll();

                System.out.println("thread 2 notify.");
            }
        }

        System.out.println("Out of thread 2");
    }
}

public class WaitAndNotify {
    public static void main(String[] args) {
        ExecutorService exec = Executors.newCachedThreadPool();
        Runnable a = new MyThread1();
        exec.execute(a);
        exec.execute(new MyThread2(a));
        exec.shutdown();
    }
}

 以上例子,wait和notify获得的都是syncObject的锁,若在synchronized方法中直接使用wait那么wait获得的锁是当前对象的锁。那么notify也必须获得与wait对应一样的锁才能唤醒wait的线程。

 

wait(Time)和sleep(Time)的区别:都表示等待Time时间后继续运行,但是wait()会释放锁,sleep不会释放锁。当没有获得锁的情况中只能使用sleep().

 

中断

t.interrupt(),t.isInterrupted(),Thread.interrupted()

t.interrupt():会设置这个线程的中断状态为true 。且对于如果一个线程已经被阻塞或者试图执行一个阻塞操作,那么这个线程会抛出InterruptedException ,对于sleep和wait方法都会默认捕捉InterruptedException方法。

 

当调用t.interrupt()后再调用t.isInterrupted()线程true。

当有别的线程调用了本线程的interrupt( )时,会设置一个标记以表示这个这个线程被打断了。当本线程捕获这个异常的时候,会清除这个标志。所以catch语句会永远报告说isInterrupted( )是false。这个标记是用来应付其它情况的,或许在没出异常的情况下,线程要用它来检查自己是不是被中断了。


Thread.interrupted()调用过后会清除了其中断状态.

 

官方API:

interrupt

public void interrupt
()
中断线程。

如果当前线程没有中断它自己(这在任何情况下都是允许的),则该线程的 checkAccess 方法就会被调用,这可能抛出 SecurityException

如果线程在调用 Object 类的 wait() wait(long) wait(long, int) 方法,或者该类的 join() join(long) join(long, int) sleep(long) sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException

如果该线程在可 中断的通道 上的 I/O 操作中受阻,则该通道将被关闭,该线程的中断状态将被设置并且该线程将收到一个 ClosedByInterruptException

如果该线程在一个 Selector 中受阻,则该线程的中断状态将被设置,它将立即从选择操作返回,并可能带有一个非零值,就好像调用了选择器的 wakeup 方法一样。

如果以前的条件都没有保存,则该线程的中断状态将被设置。

 

抛出:
SecurityException - 如果当前线程无法修改该线程

<!-- -->

interrupted

public static boolean interrupted
()
测试当前线程是否已经中断。线程的 中断状态 由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回 false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。

 

返回:
如果当前线程已经中断,则返回 true ;否则返回 false
另请参见:
isInterrupted()

<!-- -->

isInterrupted

public boolean isInterrupted
()
测试线程是否已经中断。线程的 中断状态 不受该方法的影响。

 

返回:
如果该线程已经中断,则返回 true ;否则返回 false
另请参见:
interrupted()


t.interrupt()不会中断正在执行的线程,只是将线程的标志位设置成true。但是如果线程在调用sleep(),join(),wait() 方法时线程被中断,则这些方法会抛出InterruptedException,在catch块中捕获到这个异常时,线程的中断标志位已经被设置成 false了,因此在此catch块中调用t.isInterrupted(),Thread.interrupted()始终都为false,
而t.isInterrupted与Thread.interrupted()的区别是API中已经说明很明显 了,Thread.interrupted()假如当前的中断标志为true,则调完后会将中断标志位设置成false

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值