【高并发系列】3、线程那些事儿

线程是轻量级进程,是程序执行的最小单位;

线程的生命周期:

线程基本操作:

1、新建线程

Thread t = new Thread();
t.start();

Thread的run()方法只会在当前线程中串行执行run()方法中的代码,正确开启新线程应使用start()方法;

public class CreateThread implements Runnable {

	@Override
	public void run() {
		System.out.println("CreateThread.run()");
	}

	public static void main(String[] args) {
		Thread t = new Thread(new CreateThread());
		t.start();
	}

}

默认的Thread.run()方法就是直接调用内部Runnable接口;

/* What will be run. */
private Runnable target;

/**
 * If this thread was constructed using a separate
 * <code>Runnable</code> run object, then that
 * <code>Runnable</code> object's <code>run</code> method is called;
 * otherwise, this method does nothing and returns.
 * <p>
 * Subclasses of <code>Thread</code> should override this method.
 *
 * @see     #start()
 * @see     #stop()
 * @see     #Thread(ThreadGroup, Runnable, String)
 */
@Override
public void run() {
    if (target != null) {
        target.run();
    }
}

2、终止线程

stop()方法之所以被废弃,是因为stop()方法过于暴力,强行把正在执行的线程终止,可能会引起一些数据不一致的问题;

不安全的停止线程demo:

public class StopThreadUnsafe {
	private static User u = new User();
	public static class User {
		private int id;
		private String name;
		public User() {
			id = 0;
			name = "0";
		}
		public void setId(int id) {
			this.id = id;
		}
		public int getId() {
			return id;
		}
		public void setName(String name) {
			this.name = name;
		}
		public String getName() {
			return name;
		}
		@Override
		public String toString() {
			return "User [id=" + id + ", name=" + name + "]";
		}
	}
	public static class ChangeObjectThread extends Thread {
		@Override
		public void run() {
			while (true) {
				synchronized (u) {
					int v = (int) (System.currentTimeMillis() / 1000);
					u.setId(v);
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					u.setName(String.valueOf(v));
				}
				Thread.yield();
			}
		}
	}
	public static class ReadObjectThread extends Thread {
		@Override
		public void run() {
			while (true) {
				synchronized (u) {
					if (u.getId() != Integer.parseInt(u.getName())) {
						System.out.println(u);
					}
				}
				Thread.yield();
			}
		}
	}
	@SuppressWarnings("deprecation")
	public static void main(String[] args) throws InterruptedException {
		new ReadObjectThread().start();
		while (true) {
			Thread t = new ChangeObjectThread();
			t.start();
			Thread.sleep(150);
			t.stop();
		}
	}
}

##################################################
console
User [id=1549372735, name=1549372734]
User [id=1549372735, name=1549372734]
User [id=1549372735, name=1549372734]
User [id=1549372736, name=1549372735]

正确停止线程demo:

public class StopThreadSafe {
	private static User u = new User();
	public static class User {
		private int id;
		private String name;
		public User() {
			id = 0;
			name = "0";
		}
		public void setId(int id) {
			this.id = id;
		}
		public int getId() {
			return id;
		}
		public void setName(String name) {
			this.name = name;
		}
		public String getName() {
			return name;
		}
		@Override
		public String toString() {
			return "User [id=" + id + ", name=" + name + "]";
		}
	}
	public static class ChangeObjectThread extends Thread {
		private volatile boolean stopme = false;
		public void stopMe() {
			stopme = true;
		}
		@Override
		public void run() {
			while (true) {
				if (stopme) {
					System.out.println("exit by stop me");
					break;
				}
				synchronized (u) {
					int v = (int) (System.currentTimeMillis() / 1000);
					u.setId(v);
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					u.setName(String.valueOf(v));
				}
				Thread.yield();
			}
		}
	}
	public static class ReadObjectThread extends Thread {
		@Override
		public void run() {
			while (true) {
				synchronized (u) {
					if (u.getId() != Integer.parseInt(u.getName())) {
						System.out.println(u);
					}
				}
				Thread.yield();
			}
		}
	}
	public static void main(String[] args) throws InterruptedException {
		new ReadObjectThread().start();
		while (true) {
			ChangeObjectThread t = new ChangeObjectThread();
			t.start();
			Thread.sleep(150);
			t.stopMe();
		}
	}
}

#####################
console
exit by stop me
exit by stop me
exit by stop me

3、线程中断

线程中断是一种重要的线程协作机制;

public void interrupt()                // 中断线程
public boolean isInterrupted()         // 判断是否被中断
public static boolean interrupted()    // 判断是否被中断,并清除当前中断状态
public void interrupt() {
    if (this != Thread.currentThread())
        checkAccess();
    synchronized (blockerLock) {
        Interruptible b = blocker;
        if (b != null) {
            interrupt0();           // Just to set the interrupt flag
            b.interrupt(this);
            return;
        }
    }
    interrupt0();
}
public boolean isInterrupted() {
    return isInterrupted(false);
}
public static boolean interrupted() {
    return currentThread().isInterrupted(true);
}
/**
 * Tests if some Thread has been interrupted.  The interrupted state
 * is reset or not based on the value of ClearInterrupted that is
 * passed.
 */
private native boolean isInterrupted(boolean ClearInterrupted);

 使用Thread.currentThread().isInterrupted()判断当前线程是否被中断,如果被中断了,退出循环体,结束线程;

public class InterruptThread {
	public static void main(String[] args) throws InterruptedException {
		Thread t = new Thread("interrupt") {
			@Override
			public void run() {
				while (true) {
					if (Thread.currentThread().isInterrupted()) {
						System.out.println("Interrupted!");
						break;
					}
				}
				Thread.yield();
			}
		};
		t.start();
		TimeUnit.SECONDS.sleep(2);
		t.interrupt();
	}
}

Thread.sleep()函数签名:

/**
 * Causes the currently executing thread to sleep (temporarily cease
 * execution) for the specified number of milliseconds, subject to
 * the precision and accuracy of system timers and schedulers. The thread
 * does not lose ownership of any monitors.
 *
 * @param  millis
 *         the length of time to sleep in milliseconds
 *
 * @throws  IllegalArgumentException
 *          if the value of {@code millis} is negative
 *
 * @throws  InterruptedException
 *          if any thread has interrupted the current thread. The
 *          <i>interrupted status</i> of the current thread is
 *          cleared when this exception is thrown.
 */
public static native void sleep(long millis) throws InterruptedException;

当线程在休眠被中断时会抛出InterruptedException异常,并清除中断标记,catch捕获后没有选择立即退出线程,而是设置中断标志,保证数据的一致性和完整性; 

public class InterruptSleepThread {
	public static void main(String[] args) throws InterruptedException {
		Thread t = new Thread("interrupt-sleep") {
			@Override
			public void run() {
				while (true) {
					if (Thread.currentThread().isInterrupted()) {
						System.out.println("Interrupted!");
						break;
					}
					try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						System.out.println("Interrupted when sleep.");
						// 设置中断状态
						Thread.currentThread().interrupt();
					}
				}
				Thread.yield();
			}
		};
		t.start();
		Thread.sleep(1500);
		t.interrupt();
	}
}

4、等待wait()和通知notify()

public final native void wait(long timeout) throws InterruptedException
public final native void notify()
public final native void notifyAll()

Object.wait()方法和Thread.sleep()方法都让线程等待若干时间,wait()方法可以被唤醒,并且wait()方法会释放目标对象的锁,但sleep()方法不会释放任何资源;

public class WaitNotifyDemo {
	private static final Object lock = new Object();
	public static class WaitThread extends Thread {
		@Override
		public void run() {
			synchronized (lock) {
				System.out.println(System.currentTimeMillis() + ":WaitThread start!");
				try {
					System.out.println(System.currentTimeMillis() + ":WaitThread wait for lock.");
					lock.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(System.currentTimeMillis() + ":WaitThread end!");
			}
		}
	}
	public static class NotifyThread extends Thread {
		@Override
		public void run() {
			synchronized (lock) {
				System.out.println(System.currentTimeMillis() + ":NotifyThread start!");
				lock.notify();
				System.out.println(System.currentTimeMillis() + ":NotifyThread end!");
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	public static void main(String[] args) {
		Thread waitThread = new WaitThread();
		Thread notifyThread = new NotifyThread();
		waitThread.start();
		notifyThread.start();
	}
}

1549382736972:WaitThread start!
1549382736972:WaitThread wait for lock.
1549382736972:NotifyThread start!
1549382736972:NotifyThread end!
1549382738977:WaitThread end!

5、挂起suspend()和继续执行resume()线程

/**
 * Suspends this thread.
 * <p>
 * First, the <code>checkAccess</code> method of this thread is called
 * with no arguments. This may result in throwing a
 * <code>SecurityException </code>(in the current thread).
 * <p>
 * If the thread is alive, it is suspended and makes no further
 * progress unless and until it is resumed.
 *
 * @exception  SecurityException  if the current thread cannot modify
 *               this thread.
 * @see #checkAccess
 * @deprecated   This method has been deprecated, as it is
 *   inherently deadlock-prone.  If the target thread holds a lock on the
 *   monitor protecting a critical system resource when it is suspended, no
 *   thread can access this resource until the target thread is resumed. If
 *   the thread that would resume the target thread attempts to lock this
 *   monitor prior to calling <code>resume</code>, deadlock results.  Such
 *   deadlocks typically manifest themselves as "frozen" processes.
 *   For more information, see
 *   <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
 *   are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
 */
@Deprecated
public final void suspend() {
    checkAccess();
    suspend0();
}

/**
 * Resumes a suspended thread.
 * <p>
 * First, the <code>checkAccess</code> method of this thread is called
 * with no arguments. This may result in throwing a
 * <code>SecurityException</code> (in the current thread).
 * <p>
 * If the thread is alive but suspended, it is resumed and is
 * permitted to make progress in its execution.
 *
 * @exception  SecurityException  if the current thread cannot modify this
 *               thread.
 * @see        #checkAccess
 * @see        #suspend()
 * @deprecated This method exists solely for use with {@link #suspend},
 *     which has been deprecated because it is deadlock-prone.
 *     For more information, see
 *     <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
 *     are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
 */
@Deprecated
public final void resume() {
    checkAccess();
    resume0();
}

suspend()方法挂起线程时导致线程暂停,但不会释放任何锁资源;如果resume()方法意外地在suspend()方法前就执行了,会导致被挂起的线程可能很难有机会被继续执行;并且对于被挂起的线程,从线程状态上看居然还是Runnable;

public class SuspendResumeDemo {
	public static Object lock = new Object();
	private static ChangeObjectThread t1 = new ChangeObjectThread("t1");
	private static ChangeObjectThread t2 = new ChangeObjectThread("t2");
	public static class ChangeObjectThread extends Thread {
		public ChangeObjectThread(String name) {
			super.setName(name);
		}

		@SuppressWarnings("deprecation")
		@Override
		public void run() {
			synchronized (lock) {
				System.out.println("In " + getName());
				Thread.currentThread().suspend();
			}
		}
	}
	@SuppressWarnings("deprecation")
	public static void main(String[] args) throws InterruptedException {
		t1.start();
		Thread.sleep(100);
		t2.start();
		t1.resume();
		t2.resume();
		t1.join();
		t2.join();
	}
}

In t1
In t2

(t1启动后,持有lock锁,而且suspend()方法不会释放资源,一直持有锁,当t2启动后,无法获得lock锁,t2阻塞;当t1.resume()执行后,t1继续执行,释放lock锁,此时t2获得lock锁,打印In t2,之后t2挂起;与此同时main线程中执行了t2.resume(),这个resume方法没有生效,造成t2永远挂起,并且永远占有lock锁;)

示例代码中,t2线程的resume()方法就在其suspend()方法前执行了,导致t2线程被挂起,程序不会退出,永远被挂起,并且永远占用lock对象的锁;

使用wait()方法和notify()方法模拟挂起和继续执行功能:

public class WaitNotifySimulateSuspendResumeDemo {
	public static Object lock = new Object();
	public static class ChangeObjectThread extends Thread {
		private volatile boolean suspendme = false;
		public void suspendMe() {
			suspendme = true;
		}
		public void resumeMe() {
			suspendme = false;
			synchronized (this) {
				notify();
			}
		}
		@Override
		public void run() {
			while (true) {
				synchronized (this) {
					while (suspendme) {
						try {
							wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
				synchronized (lock) {
					System.out.println("In ChangeObjectThread");
					try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				Thread.yield();
			}
		}
	}
	public static class ReadObjectThread extends Thread {
		@Override
		public void run() {
			while (true) {
				synchronized (lock) {
					System.out.println("In ReadObjectThread");
					try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				Thread.yield();
			}
		}
	}
	public static void main(String[] args) throws InterruptedException {
		ChangeObjectThread t1 = new ChangeObjectThread();
		ReadObjectThread t2 = new ReadObjectThread();
		t1.start();
		t2.start();
		Thread.sleep(1000);
		t1.suspendMe();
		System.out.println("suspend t1 2 seconds.");
		Thread.sleep(2000);
		System.out.println("resume t1");
		t1.resumeMe();
		t1.join();
		t2.join();
	}
}

6、等待线程结束join()和谦让yeild()

public final void join() throws InterruptedException
public final synchronized void join(long millis) throws InterruptedException
public class JoinDemo {
	public volatile static int i = 0;
	public static class IncrementThread extends Thread {
		@Override
		public void run() {
			for (i = 0; i < 10000000; i++)
				;
		}
	}
	public static void main(String[] args) throws InterruptedException {
		IncrementThread it = new IncrementThread();
		it.start();
		it.join();
		System.out.println(i);
	}
}

输出i的值为10000000,即it.join()保证了main线程等待IncrementThread执行完毕了之后,再输出i的值;

public static native void yield();

yield()方法会让出CPU,还会进行CPU资源的争夺,但是是否能够再次被分配时间片就不一定了;

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值