Java多线程的开启
使用Thread开启多线程
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程开启");
}
});
t.start();
wait()和sleep()的对比
wait()和sleep()都是能让线程进入休眠状态。准确的说:
1. 使用了wait方法的话,线程会进入一个等待状态,此刻,线程持有的monitor释放,同时等待获取到monitor才可以进行运行该线程。
2. 使用了sleep方法的话,线程进入一个休眠状态,使用该方法一般需要传入一个时间参数mills(毫秒),此刻同时,线程将休眠mills的时长,然后自动唤醒。
最主要的区别如下:
1. wait是Object中的方法,使用了wait方法,必须使用Object中的notify或notifyAll来唤醒线程。
2. sleep是Thread中的方法,使用了sleep方法,不需要其他操作,线程睡眠完就会自动唤醒运行。
wait方法
源码:
/**
* Causes the current thread to wait until another thread invokes the
* {@link java.lang.Object#notify()} method or the
* {@link java.lang.Object#notifyAll()} method for this object.
* In other words, this method behaves exactly as if it simply
* performs the call {@code wait(0)}.
* <p>
* 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 {@code notify} method or the
* {@code notifyAll} method. The thread then waits until it can
* re-obtain ownership of the monitor and resumes execution.
* <p>
* As in the one argument version, interrupts and spurious wakeups are
* possible, and this method should always be used in a loop:
* <pre>
* synchronized (obj) {
* while (<condition does not hold>)
* obj.wait();
* ... // Perform action appropriate to condition
* }
* </pre>
* This method should only be called by a thread that is the owner
* of this object's monitor. See the {@code notify} method for a
* description of the ways in which a thread can become the owner of
* a monitor.
*
* @throws IllegalMonitorStateException if the current thread is not
* the owner of the object's monitor.
* @throws InterruptedException if any thread interrupted the
* current thread before or while the current thread
* was waiting for a notification. The <i>interrupted
* status</i> of the current thread is cleared when
* this exception is thrown.
* @see java.lang.Object#notify()
* @see java.lang.Object#notifyAll()
*/
public final void wait() throws InterruptedException {
wait(0);
}
从源码中可以看出
1. 首先,使用wait,可以使得线程进入一个等待状态。
2. 其次,每个线程必须持有该对象的monitor。如果在当前线程中调用wait()方法之后,该线程就会释放monitor的持有对象并让自己处于等待状态。
3. 调用wait方法必须使用同步锁synchronized的代码快中.
4. 如果想唤醒该线程,必须在另一个线程中,并在synchronized代码块中使用notify或者notifyAll才能重新让线程获取到monitor,线程才能被唤醒。(一定要在另一个线程中才有效)
测试代码和结果
1. 正确的使用wait和notify例子,ThreadTest为本类
public static void main(String[] strings){
ThreadTest test = new ThreadTest();
test.waitThread();
Scanner scanner = new Scanner(System.in);
System.out.println("任意输入,唤醒线程:");
scanner.nextLine();
test.notifyWaitThread();
}
/**
* 对象锁
*/
private final Object object = new Object();
/**
*
* 使用Object.wait()方法使得线程进入等待状态,使得该线程释放了该线程拥有的monitor
* 使用wait方法,必须使用Object的notify和notifyAll来让线程重新获取到monitor对象,唤醒线程
*
*/
private void waitThread(){
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程1开启");
synchronized (object){
System.out.println("线程1进入等待状态");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("线程1结束");
}
});
t.start();
}
private void notifyWaitThread(){
synchronized(object){
System.out.println("开始唤醒等待中的线程");
object.notify();
}
}
运行的结果:
可以看出,线程被成功唤醒,其中唤醒等待线程的线程为main主线程
2. 在使用wait的线程中进行notify操作的例子,ThreadTest为本类
private void waitThread(){
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程1开启");
synchronized (object){
System.out.println("线程1进入等待状态");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
//使用notify唤醒线程
object.notify();
}
System.out.println("线程1结束");
}
});
t.start();
}
private void waitThread(){
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程1开启");
synchronized (object){
System.out.println("线程1进入等待状态");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//使用notify唤醒线程
synchronized (object){
object.notify();
}
System.out.println("线程1结束");
}
});
t.start();
}
main方法中进行了修改
public static void main(String[] strings){
ThreadTest test = new ThreadTest();
test.waitThread();
}
运行结果都是线程没有获取到monitor才处于等待的状态
sleep方法
相信很多人都用过该方法,这里直接进行简单的演示
代码
/**
* sleep是Thread的方法,可使得当前线程进入休眠状态,但是和Object的wait方法的区别在于,使用sleep方法线程没有释放对应的monitor对象,不需要通过notify来唤醒,时间走完就恢复
* @param millis
*/
private void sleepThread(long millis){
Thread thread = new Thread(()->{
System.out.println("sleepThread创建");
System.out.println("sleepThread进入睡眠状态,时长为:" + millis);
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("sleepThread睡眠结束,被唤醒了");
});
thread.start();
}
main函数中
public static void main(String[] strings){
ThreadTest test = new ThreadTest();
test.sleepThread(2000);
}
运行结果
下面简单说一下notify和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 {@code wait} methods.
* <p>
* 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.
* <p>
* 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:
* <ul>
* <li>By executing a synchronized instance method of that object.
* <li>By executing the body of a {@code synchronized} statement
* that synchronizes on the object.
* <li>For objects of type {@code Class,} by executing a
* synchronized static method of that class.
* </ul>
* <p>
* 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 java.lang.Object#notifyAll()
* @see java.lang.Object#wait()
*/
public final native void notify();
从源码可以看出
1. notify可以唤醒该monitor的第一个wait的线程,而且只唤醒一个线程
2. notify必须在另外线程中使用,并且得在synchronized代码块中执行,并且对应的锁应该是该线程的monitor持有的对象
例子:多个线程进入等待状态,使用一次notify只能唤醒第一个进入等待的线程
private class MyRunnable implements Runnable{
private String name;
public MyRunnable(String name){
this.name = name + "线程";
}
@Override
public void run() {
System.out.println(name + "启动");
synchronized (object){
try {
System.out.println(name + "进入wait状态");
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(name + "被唤醒并执行结束");
}
}
private void startAndWaitAllThread(){
String names[] = {"A", "B", "C", "D", "E"};
for (int i = 0; i < names.length; i ++){
Thread thread = new Thread(new MyRunnable(names[i]));
thread.start();
}
}
public static void main(String[] strings) throws InterruptedException {
ThreadTest test = new ThreadTest();
test.startAndWaitAllThread();
Thread.sleep(2000);
test.notifyWaitThread();
}
执行结果:
notifyAll
源码
/**
* Wakes up all threads that are waiting on this object's monitor. A
* thread waits on an object's monitor by calling one of the
* {@code wait} methods.
* <p>
* The awakened threads will not be able to proceed until the current
* thread relinquishes the lock on this object. The awakened threads
* will compete in the usual manner with any other threads that might
* be actively competing to synchronize on this object; for example,
* the awakened threads enjoy no reliable privilege or disadvantage in
* being the next thread to lock this object.
* <p>
* This method should only be called by a thread that is the owner
* of this object's monitor. See the {@code notify} method for a
* description of the ways in which a thread can become the owner of
* a monitor.
*
* @throws IllegalMonitorStateException if the current thread is not
* the owner of this object's monitor.
* @see java.lang.Object#notify()
* @see java.lang.Object#wait()
*/
public final native void notifyAll();
使用notifyAll的区别就是可以使所有的等待线程获取到monitor,并唤醒,但是顺序是随机的,下面看一下执行的效果
在main中使用notifyAll唤醒线程
public static void main(String[] strings) throws InterruptedException {
ThreadTest test = new ThreadTest();
test.startAndWaitAllThread();
Thread.sleep(2000);
test.notifyAllWaitThread();
}
执行效果
可以看出,唤醒的顺序是随机的
到这里就结束结束啦,欢迎提意见留意