Java thread overview and API 1

1 Create thread and create thread runtime code

In Java, there is only one way to create a thread, that is to create an instance of the Thread object. 运行时代码There are three ways to create a thread :

The first: inherit the Threadclass and override its runmethods.

The second: implement the Runnableinterface, implement runthe method, and the Thread class also implements the Runable interface.

The third: implement Callablethe interface and implement its callmethods, which was introduced in the java concurrent package in JDK1.5.

 

The difference between the start() method and the run() method

startThe () method is used to start the thread. After the start method is called, the thread enters the runnable state. Once the thread scheduler schedules execution, the thread enters the running state. After the thread is started, the JVM allocates corresponding resources to the thread, such as stack memory space. Then the callback thread运行时代码。

runThe () method is used to execute the runtime code of the thread. If this method is called directly, it does not create a new thread but is executed in the current thread.

 
Override the run method of the Thread object and pass in a Runnable implementation class?

We know that after the thread is created, then the JVM calls back the thread 运行时代码run(),so look at the default run()implementation of Thread:

 

/* What will be run. */
private Runnable target;
....
@Override
public void run() {
    if (target != null) {
        target.run();
    }
}

 

 The target is the Runable object. The logic of the default run method is that if the implementation class of Runnable is passed, the run method of Runnable will be run. Therefore:当覆盖了Thread对象的run方法之后,执行的肯定是覆盖之后的逻辑,原来的这段逻辑如果不存在了,

就算传入了Runnable的实现类,也不会执行。

 

Finally, the Thread object implements the Runnable interface (implementing the run method), and the constructor can accept an implementation class of the Runnable interface (which also implements the run method), which is called target. When executing, if the target exists, The run method of the target is executed. This is actually the Decorator Design Pattern (aka the Wrapper Design Pattern )

 

The difference between the sleep() method and the wait() method

The sleep() method is a static method defined in the Thread class. Its function is to make the current thread sleep and suspend execution. During the sleep period, the thread will not request the CPU to execute, so other threads (even lower priority threads) can obtain more Opportunity to run. But if the synchronization lock is held, the lock will not be released.

The sleep method has InterruptedException compile-time exceptions that need to be caught. And you cannot specify to sleep a specific thread t.sleep(), it will only make the current thread sleep instead of the t thread, so even if t.sleep(...) is called like this, it is not the t thread that is suspended. is the current thread, the correct usage should be Thread.sleep(...). When the sleep method is called, the thread enters the blocking state and does not release the occupied resources . After the sleep method ends and returns, the thread returns to the runnable state instead of the running state, and the thread scheduling mechanism is required to restore it to the running state.

 

In addition, the java.util.concurrent.TimeUnit class provides a sleep package implementation with more explicit semantics. The bottom layer still calls the Thread.sleep(...) method, but its unit is more explicit, such as sleep for 2 seconds: TimeUnit. SECONDS.sleep(2);

 

wait()方法是Object类中定义的方法,只能在同步方法或者同步代码块中调用,如果持有同步锁,会释放锁,让其他需要获得该锁的线程有机会运行。当线程调用wait()方法后会进入等待队列(进入这个状态会释放所占有的所有资源,与阻塞状态不同)

wait方法同样也可以在wait期间因为被其他对象调用interrupt()方法二产生InterruptedException运行时异常。一旦一个对象调用了wait方法,必须要采用notify()和notifyAll()方法唤醒该进程。调用wait或者notify的时候,当前线程必须要是对象lock的拥有者,否则会抛出IllegalMonitorStateException异常。

synchronized (share) {
   share.wait();
}

 当线程在synchronized中调用了share.wait()时,在放弃了CPU的同时,也放弃了share这个对象的lock,进入这个对象的wait pool。

当另外一个线程调用了share.notify()时,将从wait pool中拿出一个线程,让该线程获得lock,并进入可运行状态,等待线程调度执行。

这也就是为什么wait/notify需要加锁的原因。

 

5 线程挂起与恢复suspend/resume

suspend可以将正在执行的线程挂起暂停执行。resume即使线程从挂起状态恢复。但这两个 API 是过期的,也就是不建议使用的。因为suspend()方法在执行时不会释放线程占用的资源(比如同步锁),并且没有超时时间的设定,如果resume在suspend之前调用或者在同步块内部执行,并且同步锁已经被挂起的线程占用,那么将陷入死锁状态。对于被挂起的线程,使用jconsole查看它的线程状态居然还是 Runnable。

 

另外,System.out.println(...)也是一个同步方法, 在执行打印之前需要获取PrintStream对象锁。并且PrintStream的实例对象out是System类的一个静态实例,System类中只有唯一的一个PrintOut对象:

public void println(String x) {
        synchronized (this) {
            print(x);
            newLine();
        }
}

 

 所以下面的代码将永远无法打印出main end!,因为挂起的thread线程占用了PrintStream对象锁---out.

public class MyThread extends Thread{
	private long i = 0;
	
    @Override
    public void run() {
        while (true) {
            i++;
            System.out.println(i);//同步方法
        }
    }
    
    public static void main(String[] args) throws Exception{
    	MyThread thread = new MyThread();
    	
    	thread.start();//启动一个线程'thread'
    	
    	Thread.sleep(1000l);//使当前线程(main线程)睡眠
    	
    	thread.suspend();//挂起线程'thread'
    	
    	System.out.println("main end!");
	}
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326491590&siteId=291194637