一,线程基础

一,线程的实现

线程的实现是并发的基础。基本上我们有两种实现线程的方法,继承Thread类和实现Runnable接口。

1,实现runnable接口

public class RunnableThread implements Runnable{

  @override

  public void run(){

    System.out.println("用实现runnable接口实现线程。");

  }

}

将这个类的实例传入Thread类中就可以实现多线程了。

2,继承Thread类

public class AThread extends Thread{

  @Override

  public void run(){

    System.out.println("用继承Thread实现线程。")

  }

}

调用这个实例的start方法即可实现多线程。

还有一些扩展方法用来实现多线程。

1,线程池创建线程

static class DefaultThreadFactory implements ThreadFactory {
    DefaultThreadFactory() {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() :
            Thread.currentThread().getThreadGroup();
        namePrefix = "pool-" +
            poolNumber.getAndIncrement() +
            "-thread-";
    }
    public Thread newThread(Runnable r) {
        Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);

        if (t.isDaemon())
            t.setDaemon(false);
        if (t.getPriority() != Thread.NORM_PRIORITY)
            t.setPriority(Thread.NORM_PRIORITY);
        return t;
    }
}

可以看到,最终线程的创建也是通过new Thread()实现的。还有callable等方法也是通过线程实现的。

二,线程的终止

正确的终止是利用给线程发中断信号,线程收到后,完成一些收尾工作,然后结束。不应该通过stop,suspend,等方法,这些方法可能会破坏线程处理的数据。或者造成死锁等问题。

在java中,线程之间应该是相互协作关系,一个线程给另一个线程发送信号。收到信号的线程如何执行下面的工作应该是自己决定,而不收其他线程的控制。

所以正常希望某个线程终止,就给他发送中断信息,该线程如果在循环中,应该判断是否收到中断信息,或者在休眠和其他等待中,也会通过产生一个中断异常被唤醒,这个时候可以执行首尾工作。或者向上抛出这个异常。

三,线程的六种状态

1 new 2 runnable 3 blocked 4 waiting 5 timed waiting 6 terminated

 

四,wait,notify,notifyall

wait notify notifyall都是object对象的方法,是对象锁,不是线程锁。

 

wait 必须和synchronized一起使用。先使用synchronized获得对象的monitor锁。然后判断是否获取资源(是否需要wait),需要则调用wait方法,并释放monitor锁。等待notify。

monitor锁在这里保证判断是否需要资源和wait的原子性。

wait

Causes the current thread to wait until another thread invokes the java.lang.Object.notify() method or the java.lang.Object.notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).

当前线程进入等待状态,直到其他线程调用该对象的notify或notifyall方法。

The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

当前线程必须先拥有这个对象的monitor锁。这个线程释放这个锁然后等待其他线程notify所有等待这个对象monitor的线程。这个线程重新拿到monitor锁,并开始操作。

As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:

     synchronized (obj) {
         while (<condition does not hold>)
             obj.wait();
         ... // Perform action appropriate to condition
     }
 

This method should only be called by a thread that is the owner of this object's monitor. See the notify method for a description of the ways in which a thread can become the owner of a monitor.

wait方法只能被持有该对象的monitor的线程调用。

Throws:
IllegalMonitorStateException - if the current thread is not the owner of the object's monitor.
InterruptedException - if any thread interrupted the current thread before or while the current thread was waiting for a notification. The interrupted status of the current thread is cleared when this exception is thrown.
See Also:
java.lang.Object.notify()
java.lang.Object.notifyAll()

wait(timeout)

Causes the current thread to wait until either another thread invokes the java.lang.Object.notify() method or the java.lang.Object.notifyAll() method for this object, or a specified amount of time has elapsed.

The current thread must own this object's monitor.

This method causes the current thread (call it T) to place itself in the wait set for this object and then to relinquish any and all synchronization claims on this object. Thread T becomes disabled for thread scheduling purposes and lies dormant until one of four things happens:

  • Some other thread invokes the notify method for this object and thread T happens to be arbitrarily chosen as the thread to be awakened.
  • Some other thread invokes the notifyAll method for this object.
  • Some other thread interrupts thread T.
  • The specified amount of real time has elapsed, more or less. If timeout is zero, however, then real time is not taken into consideration and the thread simply waits until notified.

The thread T is then removed from the wait set for this object and re-enabled for thread scheduling. It then competes in the usual manner with other threads for the right to synchronize on the object; once it has gained control of the object, all its synchronization claims on the object are restored to the status quo ante - that is, to the situation as of the time that the wait method was invoked. Thread T then returns from the invocation of the wait method. Thus, on return from the wait method, the synchronization state of the object and of thread T is exactly as it was when the wait method was invoked.

A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup. While this will rarely occur in practice, applications must guard against it by testing for the condition that should have caused the thread to be awakened, and continuing to wait if the condition is not satisfied. In other words, waits should always occur in loops, like this one:

     synchronized (obj) {
         while (<condition does not hold>)
             obj.wait(timeout);
         ... // Perform action appropriate to condition
     }
 

(For more information on this topic, see Section 3.2.3 in Doug Lea's "Concurrent Programming in Java (Second Edition)" (Addison-Wesley, 2000), or Item 50 in Joshua Bloch's "Effective Java Programming Language Guide" (Addison-Wesley, 2001).

If the current thread is interrupted by any thread before or while it is waiting, then an InterruptedException is thrown. This exception is not thrown until the lock status of this object has been restored as described above.

Note that the wait method, as it places the current thread into the wait set for this object, unlocks only this object; any other objects on which the current thread may be synchronized remain locked while the thread waits.

This method should only be called by a thread that is the owner of this object's monitor. See the notify method for a description of the ways in which a thread can become the owner of a monitor.

Parameters:
timeout the maximum time to wait in milliseconds.
Throws:
IllegalArgumentException - if the value of timeout is negative.
IllegalMonitorStateException - if the current thread is not the owner of the object's monitor.
InterruptedException - if any thread interrupted the current thread before or while the current thread was waiting for a notification. The interrupted status of the current thread is cleared when this exception is thrown.
See Also:
java.lang.Object.notify()
java.lang.Object.notifyAll()

notify

Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation. A thread waits on an object's monitor by calling one of the wait methods.

唤醒一个等待该对象monitor锁的线程。如果有任何线程调用了该对象的wait方法,将会有一个被唤醒。

The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object. The awakened thread will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.

This method should only be called by a thread that is the owner of this object's monitor. A thread becomes the owner of the object's monitor in one of three ways:

这个方法只能被持有该对象的monitor锁的线程调用。

  • By executing a synchronized instance method of that object.
  • By executing the body of a synchronized statement that synchronizes on the object.
  • For objects of type Class, by executing a synchronized static method of that class.

Only one thread at a time can own an object's monitor.

Throws:
IllegalMonitorStateException - if the current thread is not the owner of this object's monitor.
See Also:
java.lang.Object.notifyAll()
java.lang.Object.wait()

 

五,生产者消费者

 ReentrantLock, Condition

A reentrant mutual exclusion Lock with the same basic behavior and semantics as the implicit monitor lock accessed using synchronized methods and statements, but with extended capabilities.

一个可重入,互斥,排他的锁,行为和语义如同一个隐含的monitor锁,但是还拥有扩展的能力。monitor锁通过synchronized定义。

A ReentrantLock is owned by the thread last successfully locking, but not yet unlocking it. A thread invoking lock will return, successfully acquiring the lock, when the lock is not owned by another thread. The method will return immediately if the current thread already owns the lock. This can be checked using methods isHeldByCurrentThread, and getHoldCount.

The constructor for this class accepts an optional fairness parameter. When set true, under contention, locks favor granting access to the longest-waiting thread. Otherwise this lock does not guarantee any particular access order. Programs using fair locks accessed by many threads may display lower overall throughput (i.e., are slower; often much slower) than those using the default setting, but have smaller variances in times to obtain locks and guarantee lack of starvation. Note however, that fairness of locks does not guarantee fairness of thread scheduling. Thus, one of many threads using a fair lock may obtain it multiple times in succession while other active threads are not progressing and not currently holding the lock. Also note that the untimed tryLock() method does not honor the fairness setting. It will succeed if the lock is available even if other threads are waiting.

It is recommended practice to always immediately follow a call to lock with a try block, most typically in a before/after construction such as:

 
 class X {
   private final ReentrantLock lock = new ReentrantLock();
   // ...

   public void m() {
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock()
     }
   }
 }}

In addition to implementing the Lock interface, this class defines a number of public and protected methods for inspecting the state of the lock. Some of these methods are only useful for instrumentation and monitoring.

Serialization of this class behaves in the same way as built-in locks: a deserialized lock is in the unlocked state, regardless of its state when serialized.

This lock supports a maximum of 2147483647 recursive locks by the same thread. Attempts to exceed this limit result in Error throws from locking methods.

Since:
1.5
Author:
Doug Lea

 

 


posted @ 2020-04-20 17:20  apple2016  阅读(111)  评论(0编辑  收藏  举报