一、实现多线程的方式 --继承Thread 和 实现Runnable接口

1.继承Thread类

Thread结构: public class Thread implements Runnable. Thread实现了Runnable 两者之间具有多态的关系。
		局限性: 不支持多继承。 但是这两种方式创建的线程在工作时的性质是一样的。

		例1: 
		public class MyThread extends Thread{
			@Override
			public void run() {
				super.run();
				System.out.println("MyThread");
			}
		}

		public class Run {
			public static void main(String[] args) {
				MyThread m = new MyThread();
				m.start();
				System.out.println("运行结束");
			}
		}

		运行结果: 	运行结束
					运行中
		注:从代码运行结果可看出 代码运行结果与执行顺序或调用顺序无关。
			线程是一个子任务,CPU随机调用。
			执行start()方法的顺序性也不代表线程的启动顺序。

2.实现Runnable 接口

解决java不能多继承的局限性

		例1: 
			public class MyRunnable implements Runnable{
				@Override
				public void run() {
					System.out.println("运行中");
				}
			}

			public class Run {
				public static void main(String[] args) {
					Runnable r = new MyRunnable();
					Thread t = new Thread(r);
					t.start();
					System.out.println("运行结束");
				}
			}
		运行结果: 	运行结束
					运行中

		从以上可以看出: 使用Thread和Runnable的执行效果是一样的。

3. 实例变量与线程安全

自定义线程类的实例变量可共享也可以不共享
		(1) 不共享
			例1:
				public class NoSharedVariable extends Thread{
					private int count = 5;
					public NoSharedVariable(String name) {
						super();
						this.setName(name);
					}
					
					@Override
					public void run() {
						super.run();
						while (count > 0) {
							count--;
							System.out.println("由" + Thread.currentThread().getName() + "计算. count=" + count);
						}
						
					}
				}

				调用:
				package com.ljx.thread;

				public class NoSharedVariableRun {
					public static void main(String[] args) {
						NoSharedVariable a = new NoSharedVariable("A");
						NoSharedVariable b = new NoSharedVariable("B");
						NoSharedVariable c = new NoSharedVariable("B");
						a.start();
						b.start();
						c.start();
					}

				}

				运行结果:   由B计算. count=4
							由B计算. count=4
							由A计算. count=4
							由B计算. count=3
							由B计算. count=3
							由B计算. count=2
							由A计算. count=3
							由B计算. count=1
							由A计算. count=2
							由B计算. count=2
							由A计算. count=1
							由B计算. count=0
							由A计算. count=0
							由B计算. count=1
							由B计算. count=0
				由运行结果可知: 每个线程都有一个自己的计数器, 互不共享。			

		(2)共享数据
			不安全情况:
				public class SharedVariable extends Thread {
					private int count = 5;
					
					@Override
					public void run() {
						super.run();
						count--;
						System.out.println("由" + Thread.currentThread().getName() + "计算. count=" + count);
					}
				}

				public class SharedVariableRun {
					public static void main(String[] args) {
						SharedVariable myThread = new SharedVariable();
						Thread a = new Thread(myThread, "A");
						Thread b = new Thread(myThread, "B");
						Thread c = new Thread(myThread, "C");
						Thread d = new Thread(myThread, "D");
						Thread e = new Thread(myThread, "E");
						a.start();
						b.start();
						c.start();
						d.start();
						e.start();
					}
				}

				运行结果: 
						由A计算. count=2
						由B计算. count=0
						由E计算. count=1
						由D计算. count=2
						由C计算. count=2
				如运行结果所示:我们要的结果是 5 4 3 2 1依次递减的,但是如A D C 结果为一样的,
				说明其同时对count进行处理 造成了非线程安全

				解决方法: 在run方法前加一个同步锁 synchronized,一次只允许一个线程调用,防止同时调用
				synchronized public void run();

4.currentThread()方法

可以返回代码段正在被哪个线程调用的信息。以上例子有体现,不再赘述

5.isAlive()方法 判断当前线程是否处于活动状态

例:
			public class AliveThread extends Thread{
				@Override
				public void run() {
					System.out.println("run=" + this.isAlive());
				}
			}

			public class AliveRun {
				public static void main(String[] args) {
					// TODO Auto-generated method stub
					AliveThread a = new AliveThread();
					System.out.println("begin ==" + a.isAlive());
					a.start();
					System.out.println("end ==" + a.isAlive());
				}
			}

			运行结果:
					begin ==false
					end ==true
					run=true
			活动状态: 指线程已经启动且尚未终止。线程处于正在运行或准备开始运行的状态,就认为线程是'存活'的
			注意:System.out.println("end ==" + a.isAlive());==true 此值是不确定的 打印true是因为线程还未执行完毕就执行了

6.sleep() 方法

其作用是在指定的毫秒数内让"正在执行的线程"休眠(暂停执行)-- this.currentThread()返回的线程
		例: 此后为省篇幅只贴上方法
			@Override
			synchronized public void run() {
				try {
					System.out.println("begin-- " + System.currentTimeMillis());
					Thread.sleep(2000);
					System.out.println("end-- " + System.currentTimeMillis());
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

			运行结果: begin-- 1577676349044
					  end--   1577676351044  差两千毫秒

7.getID() 取得线程的唯一标识

例子:
			public static void main(String[] args) {
				Thread t = Thread.currentThread();
				System.out.println(t.getId());
			}
			运行结果:1

8.停止线程

三种方法:
			(1)使用退出标志,使线程正常退出,当run方法完成后线程终止
			 (2) 使用stop() 强行终止线程,不推荐 stop suspend resume 都是作废过期的方法
			 (3) 使用interrupt方法中断线程

		8.1 停止不了的线程
			例子:
				@Override
				public void run() {
					super.run();
					for (int i = 0; i < Integer.MAX_VALUE; i++) {
						System.out.println("第" + i + "打印");
					}
				}

				public static void main(String[] args) {
					try {
						InterruptThread i = new InterruptThread();
						i.start();
						Thread.sleep(2000);
						i.interrupt();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}

				运行结果:
						第204867937打印
						第204867938打印
						第204867939打印
						...............
						停止不了
		8.2判断线程是否是停止状态
			(1)this.interrupted();测试当前线程是否已经中断 执行后将状态标志清除为false
			 (2) this.isInterrupted();测试线程是否已经中断 不清除状态标志

		8.3能停止的线程————异常法
			例:
				@Override
				public void run() {
					super.run();
					for (int i = 0; i < Integer.MAX_VALUE; i++) {
						if (this.isInterrupted()) {//如果线程状态停止跳出循环
							System.out.println("停止运行!");
							break ;
						}
						System.out.println("第" + i + "打印");
					}
					System.out.println("此处还可以继续执行");
				}

				public static void main(String[] args) {
					try {
						StopThreadWithException stop = new StopThreadWithException();
						stop.start();
						Thread.sleep(1000);
						stop.interrupt();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}

				运行结果: ......
						  第174268打印
						  第174269打印
						  第174270打印
						  停止运行!
						  此处还可以继续执行
				以上结果显示: 线程结束后还会继续执行

				解决办法: 
					@Override
					public void run() {
						super.run();
						try {
							for (int i = 0; i < Integer.MAX_VALUE; i++) {
								if (this.isInterrupted()) {//如果线程状态停止跳出循环
									System.out.println("停止运行!");
									throw new InterruptedException();
								}
								System.out.println("第" + i + "打印");
							}
							System.out.println("此处还可以继续执行");
						} catch(InterruptedException e) {
							System.out.println("捕获到异常");
						}
					}
					在run方法中 进行手动抛出中断异常

					运行结果:   ......
							    第173703打印
								第173704打印
								停止运行!
								捕获到异常
		8.4 在沉睡中停止
			例:
				@Override
				public void run() {
					super.run();
					try {
						System.out.println("begin----");
						Thread.sleep(200000);
						System.out.println("end------");
					} catch (InterruptedException e) {
						System.out.println("捕获到异常" + this.isInterrupted());
					}
				}

				public static void main(String[] args) {
					try {
						SleepInterruptThread si = new SleepInterruptThread();
						si.start();
						Thread.sleep(200);
						si.interrupt();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				运行结果:
						begin----
						捕获到异常false
				如果在沉睡中被停止:就会遇到中断异常 并清除中断标志为false

			中断遇到中止
				@Override
				public void run() {
					super.run();
					try {
						for (int i = 0; i < 10; i++) {
							System.out.println("第" + i + "打印");
						}
						System.out.println("begin----");
						Thread.sleep(200);
						System.out.println("end------");
					} catch (InterruptedException e) {
						System.out.println("捕获到异常" +  this.isInterrupted());
					}
				}

				public static void main(String[] args) {
					SleepInterruptThread si = new SleepInterruptThread();
					si.start();
					si.interrupt();
				}
		8.5 暴力停止
			例子:
				private int i = 0;
				@Override
				public void run() {
					try {
						while(true) {
							i++;
							System.out.println("第" + i + "打印");
							Thread.sleep(1000);
						}
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}

				public static void main(String[] args) {
					try {
						ViolenceStopThread v = new ViolenceStopThread();
						v.start();
						v.sleep(9000);
						v.stop();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				运行结果:......
						第7打印
						第8打印
						第9打印
				在第九次的时候被暴力停止  注意不建议使用此方法!

		8.6 方法stop()与 ThreadDeath异常
				public void run() {
					try {
						System.out.println("停止前");
						this.stop();
						System.out.println("停止后");
					} catch (ThreadDeath e) {
						System.out.println("报ThreadDeath异常了");
					}
				}

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

				运行结果:
						停止前
						报ThreadDeath异常了

		8.7释放锁的不良后果
			例子:
				synchronized public void printStr(String username, String password) {
					try {
						this.username  = username;
						Thread.sleep(100000);
						this.password = password;
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}

				public class SynchronizedObjectThread extends Thread {
					private SynchronizedObject object;
					
					public SynchronizedObjectThread(SynchronizedObject object) {
						super();
						this.object = object;
					}
					@Override
					public void run() {
						object.printStr("b", "bb");
					}
				}

				public class SynchronizedObjectThreadRun {

					public static void main(String[] args) {
						try {
							SynchronizedObject obj = new SynchronizedObject();
							SynchronizedObjectThread objThread = new SynchronizedObjectThread(obj);
							objThread.start();
							Thread.sleep(500);
							objThread.stop();
							System.out.println(obj.getUsername() + "  " + obj.getPassword());
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}

				输出结果:b aa

		8.8使用return 停止线程
			@Override
			public void run() {
				while(true) {
					if (this.isInterrupted()) {
						System.out.println("停止了!");
						return;
					}
					System.out.println("timer" + System.currentTimeMillis());
				}
			}

			public static void main(String[] args) {
				try {
					StopThreadWithReturn s = new StopThreadWithReturn();
					s.start();
					Thread.sleep(1000);
					s.interrupt();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}

			运行结果:.....
					timer1577845081443
					timer1577845081443
					timer1577845081443
					停止了!
			建议使用异常停止线程 因为异常可以向上抛

9.暂停线程

9.1 suspend与resume方法的使用
				suspend: 暂停
				resume: 唤醒
				不推荐使用 suspend() 去挂起线程的原因,是因为 suspend() 在导致线程暂停的同时,并不会去释放任何锁资源。其他线程都无法访问被它占用的锁。直到对应的线程执行 resume() 方法后,被挂起的线程才能继续,从而其它被阻塞在这个锁的线程才可以继续执行。
				SuspendAndResumeThread thread = new SuspendAndResumeThread();
				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);
				System.out.println("B= " + System.currentTimeMillis() + " i=" + thread.getI());
				System.out.println("B= " + System.currentTimeMillis() + " i=" + thread.getI());

				运行结果:
					A= 1577850949485 i=2544173612
					A= 1577850954486 i=2544173612      
					B= 1577850954486 i=2544177579		详情请看B
					B= 1577850959486 i=5097346394
					C= 1577850959486 i=5097406539
					C= 1577850964487 i=5097406539

			9.2 suspend与resume的缺点---独占
				9.1有简略说道 suspend与resume的缺点 下面详细说明
				例子:
					public class SRSynchronizedObject {
						synchronized public void printString() {
							System.out.println("begin");
							if (Thread.currentThread().getName().equals("a")) {
								System.out.println("a 线程永远suspend了");
								Thread.currentThread().suspend();
								System.out.println("end");
							}
							System.out.println("你猜猜你能不能见到这条消息?");
						}
					}

					public static void main(String[] args) {
						try {
							final SRSynchronizedObject  object = new SRSynchronizedObject();
							Thread thread1 = new Thread() {
								@Override
								public void run() {
									object.printString();
								}
							};
							thread1.setName("a");
							thread1.start();
							Thread.sleep(1000);
							
							Thread thread2 = new Thread() {
								@Override
								public void run() {
									System.out.println("线程2");
									object.printString();
									System.out.println("线程2你猜猜能不能进来?");
								}
							};
							thread2.start();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}

					运行结果:
						begin
						a 线程永远suspend了
						线程2
						线程a被永远挂起 没办法执行了 得等到其它线程唤醒它

			9.3 suspend与resume的缺点---未同步
				例子:
					private String username = "1";
					private String password = "11";
					
					public void setVlaue(String u, String p) {
						this.username = u;
						if (Thread.currentThread().getName().equals("a")) {
							System.out.println("停止a线程");
							Thread.currentThread().suspend();
						}
						this.password = p;
					}
					
					public void printStr() {
						System.out.println(username + " " + password);
					}

					public static void main(String[] args) throws InterruptedException {
						final OutOfSyncThread o = new OutOfSyncThread();
						Thread thread1 = new Thread() {
							public void run() {
								o.setVlaue("a", "aa");
							}
						};
						thread1.setName("a");
						thread1.start();
						Thread.sleep(500);
						Thread thread2 = new Thread() {
							public void run() {
								o.printStr();
							}
						};
						thread2.start();
					}
					运行结果: a 11
					分析: 线程thread1运行到suspend 被挂起了 所以password并没有被赋值。

10. yield方法

作用:放弃当前的CPU资源,将它让给其它的任务去占用CPU执行时间。但是放弃的时间不确定 有可能刚刚放弃,马上又获得CPU时间段
					例子:
						@Override
						public void run() {
							long beginTime = System.currentTimeMillis();
							int count = 0;
							for (int i = 0; i < Integer.MAX_VALUE; i++) {
								Thread.yield();
								count = count + (i + 1);
							}
							long endTime = System.currentTimeMillis();
							
							System.out.println("用时:" + (endTime - beginTime) + "毫秒!");
						}

						调用线程的运行结果:用时:167526毫秒!
						分析:yield() 把cpu资源大方的让给其它任务啦 要对比请注释掉Thread.yield()试试

11.线程的优先级

优先级高的得到的CPU资源也比较多
				设置线程优先级用setPriority();
				java中线程的优先级分为1~10这10个等级 在这个氛围之外 jdk会抛出IllegalArgumentException();
				三个常量:MIN_PRIORITY = 1; NORM_PRIORITY = 5; MAX_PRIORITY = 10;

				11.1 优先级的继承特性
					例子:
						public class PriorityThread1 extends Thread {
							@Override
							public void run() {
								System.out.println("PriorityThread1 priority=" + this.getPriority());
								PriorityThread2 thread2 = new PriorityThread2();
								thread2.start();
							}
						}

						public class PriorityThread2 extends Thread {
							@Override
							public void run() {
								System.out.println("PriorityThread2 priority=" + this.getPriority());
							}
						}

						public static void main(String[] args) {
							System.out.println("Main Thread begin priority=" + Thread.currentThread().getPriority());
							Thread.currentThread().setPriority(6);
							System.out.println("Main Thread end priority=" + Thread.currentThread().getPriority());
							PriorityThread1 p1 = new PriorityThread1();
							p1.start();
						}
						运行结果:
								Main Thread begin priority=5
								Main Thread end priority=6
								PriorityThread1 priority=6
								PriorityThread2 priority=6
						分析:main线程启动p1线程 p1启动p2线程 他们的权限级别是一样的

				11.2 优先级具有规则性
					例子:
						@Override
						public void run() {
							long beginTime = System.currentTimeMillis();
							long addResult = 0;
							for (int i = 0; i < 10; i++) {
								for (int j = 0; j < 1000000; j++) {
									Random random = new Random();
									random.nextInt();
									addResult = addResult + i;
								}
							}
							long endTime = System.currentTimeMillis();
							System.out.println("***** thread 1 use time" + (endTime - beginTime));
						}
						注: 其实中间的双重for循环没有什么作用 只是用来消耗时间而已 并让你更清楚的看运行顺序

						public static void main(String[] args) {
							for (int i = 0; i < 5; i++) {
								PriorityFunctionThread1 p1 = new PriorityFunctionThread1();
								p1.setPriority(10);
								p1.start();
								PriorityFunctionThread2 p2 = new PriorityFunctionThread2();
								p1.setPriority(1);
								p2.start();
							}
						}

							运行结果:
								***** thread 1 use time7240
								***** thread 1 use time7754
								***** thread 1 use time9869
								***** thread 1 use time9922
								***** thread 1 use time9948
								***** thread 2 use time12246
								***** thread 2 use time12476
								***** thread 2 use time12679
								***** thread 2 use time12750
								***** thread 2 use time12804
						分析:优先级高的先运行完。 试试调换下线程1 和 线程2 的优先级别

				11.3 优先级具有随机性
					不是说优先级会改变 而是说不一定优先级高一定先执行完。
					优先级高的 只是它执行的频率高了些

12 守护线程

java线程中有两种线程,一种是用户线程,另一种是守护线程。
				守护线程是用户线程的伴生线程。如果没有用户线程 则也没有守护线程
				只有当jvm内最后一个非守护线程结束时,守护线程才会随着JVM一同结束工作。
				典型的守护线程是:垃圾回收线程
				例子:
					public class DaemonThread extends Thread {
						private int i = 0;
						@Override
						public void run() {
							try {
								while(true) {
									i++;
									System.out.println("i=" + i);
									Thread.sleep(1000);
								}
							} catch(InterruptedException e) {
								e.printStackTrace();
							}
						}
					}

					public static void main(String[] args) {
						try {
							DaemonThread d = new DaemonThread();
							d.setDaemon(true);
							d.start();
							Thread.sleep(5000);
							System.out.println("一切都结束了");
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					运行结果:
							i=1
							i=2
							i=3
							i=4
							i=5
							一切都结束了