多线程核心技术 Chapter1

多线程核心技术 技能基础Charpter1

本章需要着重掌握的是

  • 线程的启动
  • 如何使线程暂停
  • 如何使线程停止
  • 线程的优先级
  • 线程安全相关的问题

1.1 进程和多线程的概念及多线程的优点

1.2 使用多线程

1.2.1 继承Thread类
1.2.2 实现Runnable接口
1.2.3 实例变量与线程安全
1.2.4 留意i-- 与 System.out.println()的异常

1.3 currentThread()方法

1.4 isAlive()方法

1.5 sleep()方法

1.6 getId()方法

1.7 停止线程(异常法)

  /**
    * stop()方法已经弃用,unsafe
	 * interrupted()判断中断状态、并清除状态
	 * isInterrupted()判断中断状态,不清除状态
	 * interrupt() 停止线程的主要方法,但他不是真正终止一个正在运行的线程,只是在当前线程中打上一个停止标记,还需要加入一个判断才可以完成线程停止.
	 * @author Hasee
	 *
	 */
public class Test11 {
		public static void main(String[] args) {
			 try {
	//		Thread.currentThread().interrupt();
			 MyThread11 thread = new MyThread11();
			 thread.start();
			 Thread.sleep(2000);
			 thread.interrupt();
			System.out.println("是否停止1? =" + Thread.currentThread().isInterrupted());
			System.out.println("是否停止2? =" + Thread.currentThread().isInterrupted());
	
			 }
			 catch (InterruptedException e) {
			 System.out.println("main catch");
			 e.printStackTrace();
			 }
			System.out.println("end!");
		}
	}
	
	class MyThread11 extends Thread {
		@Override
		public void run() {
			for (int i = 0; i < 500; i++) {
				System.out.println("i=" + (i + 1));
			}
		}
	}

以上可以看出当前线程是main,所以从未中断过.

	/**
	 * 同样来看下段代码
	 * 
	 * @author Hasee
	 *
	 */
	public class Test14 {
		public static void main(String[] args) {
			try {
				MyThread11 thread = new MyThread11();
				thread.start();
				Thread.sleep(1000);// 暂停当前线程1s
				thread.interrupt();
				System.out.println("是否停止1? =" + thread.isInterrupted());
				System.out.println("是否停止2? =" + thread.isInterrupted());
			} catch (InterruptedException e) {
				System.out.println("main catch");
				e.printStackTrace();
			}
			System.out.println("end!");
	
		}
	}

可以看出,isInterrupted()并不清除状态.

/**
	 * 在for循环中避免出现bug,可以抛出中断异常来处理
	 * @author Hasee
	 *
	 */
	public class Test13 {
		public static void main(String[] args) {
			try {
				MyThread13 thread = new MyThread13();
				thread.start();
				Thread.sleep(2000);
				thread.interrupt();
			} catch (InterruptedException e) {
	
			}
		}
	}
	
	class MyThread13 extends Thread {
		@Override
		public void run() {
			super.run();
			try {
				for (int i = 0; i < 500000; i++) {
					if (this.isInterrupted()) {
						System.out.println("isInterrupted = " + this.isInterrupted());
						System.out.println("已经是停止状态了,我要退出.");
						throw new InterruptedException();
					}
					System.out.println("i=" + (i + 1));
				}
				System.out.println("我在for下面");
			} catch (InterruptedException e) {
				System.out.println("进MyThread13类的run方法中的catch了!");
				e.printStackTrace();
			}
			System.out.println("end.");
		}
	}

如果不抛出异常的话,直接break会执行for循环之后的语句,没有达到中断的效果.这个叫做停止线程--异常法.

1.7.1在沉睡中停止
	/**
	 * 在沉睡中停止
	 * @author Hasee
	 *
	 */
	public class Test15 {
		public static void main(String[] args) {
			try {
				MyThread16 thread2 = new MyThread16();
				thread2.start();
				thread2.interrupt();
				System.out.println("end!");
				
				MyThread15 thread = new MyThread15();
				thread.start();
				Thread.sleep(200);
				thread.interrupt();
			} catch (InterruptedException e) {
				System.out.println("main catch");
			}
			System.out.println("end!");
		}
	}
	
	//主方法中先sleep再用interrupt()
	class MyThread15 extends Thread {
		@Override
		public void run() {
			super.run();
			try {
				System.out.println("run begin");
				Thread.sleep(200000);
				System.out.println("run end");
			} catch (InterruptedException e) {
				System.out.println("在沉睡中被停止! 进入catch!" + this.isInterrupted());
				e.printStackTrace();
			}
		}
	}
	
	//
	class MyThread16 extends Thread {
		@Override
		public void run() {
			super.run();
			try {
				for(int i = 0; i < 10000; i++) {
					System.out.println("i=" + (i+1));
				}
				System.out.println("run begin");
				Thread.sleep(200000);
				System.out.println("run end");
			} catch (Exception e) {
				System.out.println("先停止,再遇到sleep!进入catch");
				e.printStackTrace();
			}
		}
	}

以上是在沉睡中停止,可以先sleep和后sleep

1.7.2 stop()暴力停止,已经弃用

使用stop()释放锁会给数据造成不一致性的结果.
示例如下:

public class TestStop1 {
		public static void main(String[] args) {
			try {
				SynchronizedObject object = new SynchronizedObject();
				MyThreadStop1 mts1 = new MyThreadStop1(object);
				mts1.start();
				Thread.sleep(500);
				mts1.stop();//强制停止,不建议在程序中用stop()
				System.out.println(object.getUsername() + " " + object.getPassword());
	
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	class SynchronizedObject {
		private String username = "a";
		private String password = "aa";
	
		public String getUsername() {
			return username;
		}
	
		public void setUsername(String username) {
			this.username = username;
		}
	
		public String getPassword() {
			return password;
		}
	
		public void setPassword(String password) {
			this.password = password;
		}
	
		synchronized public void printString(String username, String password) {
			try {
				this.username = username;
				Thread.sleep(100000);
				this.password = password;
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	class MyThreadStop1 extends Thread {
		private SynchronizedObject object;
	
		public MyThreadStop1(SynchronizedObject object) {
			this.object = object;
		}
	
		@Override
		public void run() {
			super.run();
			object.printString("b", "bb");
		}
	}
1.7.3 使用return停止线程

就是直接判断isInterrupted()状态后进行return,建议还是使用抛异常来操作

1.8 暂停线程(线程可恢复)

1.8.1 suspend和resume方法的使用
  • 可用suspend来暂停线程
  • 可用resume来恢复线程

示例如下:

public class TestSuspend_Resume {
	public static void main(String[] args) {
			try {
					Suspend_Resume_Thread thread = new Suspend_Resume_Thread();
					thread.start();
					Thread.sleep(5000);
					// A段
					thread.suspend();
					System.out.println("A= " + System.currentTimeMillis() + " i=" + thread.getI());
					Thread.sleep(5000);
					System.out.println("A= " + System.currentTimeMillis() + " i=" + thread.getI());
					// B段
					thread.resume();
					Thread.sleep(5000);
					// C段
					thread.suspend();
					System.out.println("B= " + System.currentTimeMillis() + " i=" + thread.getI());
					Thread.sleep(5000);
					System.out.println("B= " + System.currentTimeMillis() + " i=" + thread.getI());
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
class Suspend_Resume_Thread extends Thread {
	private long i = 0;	
	public long getI() {
				return i;		
	}
	public void setI(long i) {
				this.i = i;
	}
		
	@Override			
	public void run() {
				super.run();
				while (true)
					i++;
			};
		}
1.8.2 suspend与resume方法的缺点——独占

造成公共的同步对象的独占,使得其他线程无法访问公共同步对象。
如下示例:

public class TestResume_Suspend2 {
		public static void main(String[] args) {
			try {
				final SynchronizedObject1 object = new SynchronizedObject1();
				Thread thread1 = new Thread() {
					public void run() {
						object.printString();
					};
				};
				thread1.setName("a");
				thread1.start();
				Thread.sleep(1000);
				Thread thread2 = new Thread() {
				public void run() {
						System.out.println("thread2启动了,但进入不了printString方法!,只打印1个begin");
						System.out.println("因为printString()方法被a线程锁定并且永远suspend暂停了!");
						object.printString();//不能再被访问
					};
				};
				thread2.start();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				System.out.println("I love YJY");;
			}
		}
	}
	
	class SynchronizedObject1{
		synchronized public void printString() {
			System.out.println("begin");
			if(Thread.currentThread().getName().equals("a")) {
				System.out.println("a线程永远suspend了!");
				Thread.currentThread().suspend();
			}
		}
	}

以上代码即锁死了Object调用pringString()方法。
特别要注意System.out.println()方法是带同步锁的,如果内部suspend的话,同步锁没有被释放,会造成死锁。

suspend与resume方法的缺点——不同步

因为暂停而导致数据不同步。

	public class TestResume_Suspend3 {
		public static void main(String[] args) {
			try {
				final MyObject object = new MyObject();
				Thread thread1 = new Thread() {
					public void run() {
						object.setValue("a", "aa");
					};
				};
				thread1.setName("a");
				thread1.start();
				Thread.sleep(500);
				Thread thread2 = new Thread() {
					public void run() {
						object.printUsernamePassword();
					};
				};
				thread2.start();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				System.out.println("I love YJY");
	
			}
		}
	}
	
	class MyObject {
		private String username = "1";
		private String password = "11";
	
		public void setValue(String u, String p) {
			this.username = u;
			//如果当前线程名为a,则进行线程暂停
			if (Thread.currentThread().getName().equals("a")) {
				System.out.println("停止a线程!");
				Thread.currentThread().suspend();
			}
			this.password = p;
		}
		public void printUsernamePassword() {
			System.out.println(username + " " + password);
		}
	}

以上即为不同步的情况。

1.9 yield方法

该方法作用是放弃当前的cpu资源,将它让给其他的任务去占用cpu执行时间,但放弃的时间不确定。

public class TestYield {
		public static void main(String[] args) {
			YieldThread thread = new YieldThread();
			thread.start();
		}
	}
	class YieldThread extends Thread {
		@Override
		public void run() {
			long beginTime = System.currentTimeMillis();
			int count = 0;
			for (int i = 0; i < 5000000; i++) {
				Thread.yield();//将CPU让给其它资源导致最终执行完的速度变慢
				count = count + (i + 1);
			}
			long endTime = System.currentTimeMillis();
			System.out.println("用时:" + (endTime - beginTime) + "毫秒!");
		}
	}

1.10 线程的优先级

  • 优先级较高的线程得到的CPU资源较多
  • 线程优先具有继承性---->比如A线程启动B线程,则B线程的优先级与A是一样的
  • 高优先级总是大部分先执行完,但不代表高优先级的线程总是全部先执行完
  • 当线程优先级的等级差距很大时,谁先执行完和代码的调用顺序无关
  • 即优先级越高,CPU尽量将执行资源让给优先级高的线程,1-10,10是最高优先级
  • 优先级具有随机性,优先级较高的线程不一定每一次都先执行完

1.11 守护线程

Java中有两种线程,一种是用户线程,另外一种就是守护线程(Daemon线程)
典型的守护进程就是垃圾回收线程,当进程中没有非守护线程了,则垃圾回收线程也就没有存在的必要的。
GC就是典型的垃圾回收器。

总结

主要就是开篇的几个要点,然后对API的使用,以及Synchronized关键字的基本使用。

posted @ 2018-10-19 12:22  AM24  阅读(89)  评论(0)    收藏  举报