1.进程和线程的定义
进程:受操作系统管理的基本运行单元
线程:进程中独立运行的子任务
2.使用多线程
2.1继承Thread类:自定义线程类并继承Thread类,并且重写run方法。
class MyThread extends Thread { private int count=1000; @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<500;i++){ count--; System.out.println(Thread.currentThread().getId()+":"+count); } } } public class Test { /** * @param args * @throws ClassNotFoundException * @throws IOException */ public static void main(String[] args) { // TODO Auto-generated method stub MyThread myThread=new MyThread(); for(int i=0;i<2;i++){ Thread thread=new Thread(myThread); thread.start(); } } }
Thread类start()方法其实就是开始接受由操作系统分配的时间片,一但当前线程接受到时间片就开始执行run()方法
2.2实现Runnable接口(推荐)
class MyThread implements Runnable { private int count=1000; @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<500;i++){ count--; System.out.println(Thread.currentThread().getId()+":"+count); } } } public class Test { public static void main(String[] args) throws ClassNotFoundException, IOException { // TODO Auto-generated method stub MyThread myThread=new MyThread(); for(int i=0;i<2;i++){ Thread thread=new Thread(myThread); thread.start(); } } }
3.实例变量和线程安全
3.1不共享数据的情况
class MyThread extends Thread { private int count=10; @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<5;i++){ count--; System.out.println(Thread.currentThread().getId()+":"+count); } } } public class Test { public static void main(String[] args){ // TODO Auto-generated method stub for(int i=0;i<2;i++){ Thread thread=new MyThread(); thread.start(); } } }
3.2共享数据的情况
class MyThread extends Thread { private int count=10; @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<5;i++){ count--; System.out.println(Thread.currentThread().getId()+":"+count); } } } public class Test { public static void main(String[] args){ // TODO Auto-generated method stub Thread thread1=new MyThread(); for(int i=0;i<2;i++){ Thread thread=new Thread(thread1); thread.start(); } } }
3.3非线程安全:多个线程对同一个对象实例的变量进行操作时,出现值不同步、被其它线程更改进而影响程序的执行。
4.停止线程
4.1Thread类interrupt()方法中断线程,该方法实质上只是改变了线程的中断状态,所以就算interrupt()方法被调用,
线程还是会继续执行直至结束。
class MyThread extends Thread { @Override public void run() { for(int i=0;i<Integer.MAX_VALUE;i++) { if(!this.interrupted()) { System.out.println(i); } else { System.out.println("当前线程被中断,我要退出"); break; } } System.out.println("这里是线程被中止后的输出,理论上线程被中止 我不应该被输出");// } } public class Test { public static void main(String[] args){ // TODO Auto-generated method stub Thread thread1=new Thread(new MyThread()); thread1.start(); try { Thread.sleep(2000); thread1.interrupt(); } catch (InterruptedException e) { // TODO Auto-generated catch block System.out.println("main catch"); e.printStackTrace(); } } }
运行结果:
……
328198
328199
328200
328201
328202
328203
328204
当前线程被中断,我要退出
这里是线程被中止后的输出,理论上线程被中止 我不应该被输出
4.2异常法中止线程:获取到当前线程的中止状态为true后抛出InterruptedException异常
class MyThread extends Thread { @Override public void run() { try { for(int i=0;i<Integer.MAX_VALUE;i++) { if(!this.interrupted()) { System.out.println(i); } else { System.out.println("当前线程被中断,我要退出"); throw new InterruptedException(); } } System.out.println("这里是线程被中止后的输出,理论上线程被中止 我不应该被输出");// } catch(Exception e) { System.out.println("进入到异常");// } } } public class Test { public static void main(String[] args){ // TODO Auto-generated method stub Thread thread1=new Thread(new MyThread()); thread1.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block System.out.println("main catch"); e.printStackTrace(); } thread1.interrupt(); } }
4.3使用return 中止线程:
class MyThread extends Thread { @Override public void run() { for(int i=0;i<Integer.MAX_VALUE;i++) { if(!this.interrupted()) { System.out.println(i); } else { System.out.println("当前线程被中断,我要退出"); return; } } System.out.println("这里是线程被中止后的输出,理论上线程被中止 我不应该被输出");// } } public class Test { public static void main(String[] args){ // TODO Auto-generated method stub Thread thread1=new Thread(new MyThread()); thread1.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block System.out.println("main catch"); e.printStackTrace(); } thread1.interrupt(); } }
5.暂停和恢复线程
5.1suspend和resume的使用
class MyThread extends Thread { @Override public void run() { for(int i=0;i<Integer.MAX_VALUE;i++) { System.out.println(i); } } } public class Test { public static void main(String[] args) throws InterruptedException{ // TODO Auto-generated method stub Thread thread1=new Thread(new MyThread()); thread1.start(); while(true) { Thread.sleep(3000); thread1.suspend(); Thread.sleep(3000); thread1.resume(); } } }
5.2suspend和resume方法的缺点-独占
在当前线程使用suspend和resume方法时,其它线程将无法访问公共同步对象。
class MyThread extends Thread { @Override public void run() { for(int i=0;i<Integer.MAX_VALUE;i++) { System.out.println(i); if(i>100) { this.currentThread().suspend(); } } } } public class Test { public static void main(String[] args) throws InterruptedException{ // TODO Auto-generated method stub MyThread myThread=new MyThread(); Thread thread1=new Thread(myThread); Thread thread2=new Thread(myThread); thread1.start(); Thread.sleep(3000); thread2.start(); } }
5.3suspend和resume方法的缺点-不同步
容易出现因为线程的暂停而导致数据的不同步
class MyThread extends Thread { private String username="a"; private String password="a1"; public void SetValue(String u,String p) throws InterruptedException { this.username=u; if(u=="b") { this.currentThread().suspend(); Thread.sleep(4000); this.currentThread().resume(); } this.password=p; } @Override public void run() { System.out.println(this.currentThread().getId()+"username:"+username); System.out.println(this.currentThread().getId()+"password:"+password); } } public class Test { public static void main(String[] args) throws InterruptedException{ // TODO Auto-generated method stub MyThread myThread=new MyThread(); Thread thread1=new Thread(myThread); thread1.start(); myThread.SetValue("b", "b1"); } }
6.yield方法:暂停当前正在执行的线程对象,并执行其他线程。放弃当前CPC分配给它的时间片,但放弃的时间不确定。