线程的学习笔记

来源:互联网 发布:五金 用进销存软件 编辑:程序博客网 时间:2024/06/05 02:54

线程的概念:线程是一个程序里面不同的执行路径,(一个进程里面有个主线程,叫main方法),在同一个时间点上,一个CPU只能支持一个线程在执行,java的线程是通过java.lang.thread来实现的

1:可以通过创建Thread的实例来创建新的线程

2:每个线程都是通过特定Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体,通过调用Thread类的start()方法来启动一个线程

进程的概念:进程是一个静态的概念

两种方式来创建新的线程

第一种:定义线程类实现Runnable接口

Thread myThread = new Thread(target);//target为Runnable接口类型

Runable中只有一个方法:public void run();用于定义线程运行体

使用Runnable接口可以为多个线程提供共享的数据

在实现Runnable接口的类的run方法定义中可以使用Thread的静态方法  public static Thread currentThread() 获取当前线程的引用

 第二种

可以定义一个Thread的子类并重写其run()方法,如

class MyThread extends Thread{

public void run(){}

}

然后生成该类的对象:MyThread myThread = new MyThread()

第一种创建线程的方式

//第一种创建线程的方式,实现Runnable接口,将实现了Runable接口的对象作为参数放到Thread线程中去,调用thread的start方法public class TestThread1{public static void main(String[] args){Runnable1 run1 = new Runnable1();//run1.run();//若这样调用,相当于方法的调用,线程仍然只有一个main线程,先把Runnable1线程执行完之后然后再执行main方法中的线程Thread thread1 = new Thread(run1);thread1.start();//必须要调用thread中的start方法,相当于通知CPU。该线程已经准备就绪,当有时间时候请给与执行for(int i = 0;i<100;i++){System.out.println("main: "+i);}}}class Runnable1 implements Runnable{public void run(){for(int i =0;i<100;i++){System.out.println("Runnable1: "+i);}}}

该程序中若是调用run1.run();程序的执行过程如下

若是调用Thread的start()方法,执行效果如下图

第二种创建线程的方式:

//第二种创建线程的方式,继承Thread类,直接调用该实现了Thread类的start()方法创建一个线程public class TestThread2{public static void main(String[] args){Runnable1 run1 = new Runnable1();    run1.start();for(int i = 0;i<100;i++){System.out.println("main: "+i);}}}class Runnable1 extends Thread{public void run(){for(int i =0;i<100;i++){System.out.println("Runnable1: "+i);}}}

最好是采用第一种的实现接口的方式来创建线程,因为第一种方式比较灵活,可以继承某一个类,然后又可以实现其他的类,而第二种方式就只能是继承某一个类,一般都用第一种创建线程的方式





import java.util.*;public class TestInterrupt{public static void main(String[] args){MyThread thread = new MyThread();thread.start();try{Thread.sleep(10000);//这里的Thread是调用main主线程的Thread}catch (InterruptedException e){}thread.interrupt();//当过了10秒之后对打断该线程}}class MyThread extends Thread //在这里只能用第二种创建线程的方式,因为第一种实现runnable接口的方式并没有sleep方法,只有Thread类才有sleep方法{public void run(){while (true){System.out.println("---"+new Date()+"---");try{sleep(1000);}catch (InterruptedException e) //该异常必须捕获,不能从run方法中抛出,因为run方法是继承父类的方法,子类不能抛出父类为抛出的方法{return;}}}}


测试join()方法,join方法也是会抛出异常的,所以将异常进行捕获

//测试线程的join方法public class TestJoin{public static void main(String[] args){Thread2 myThread = new Thread2("abl");myThread.start();try{myThread.join();//join()方法是相当于调用run方法,将方法合并到main线程中来,不是两个线程在跑}catch (InterruptedException e){return ;}for(int i = 0;i<10;i++){System.out.println("i am Thread");}}}class Thread2 extends Thread{Thread2(String s){super(s);}public void run(){ for(int i =0 ;i<10;i++){ System.out.println("i am "+getName()); try {sleep(1000); } catch (InterruptedException e) { return ; } }}}

其中join方法的执行路线图如下所示:


测试yeild方法,执行该方法会让其他的线程先执行

//测试yield()方法,该方法的作用是暂停当前正在执行的线程对象,并执行其他线程public class TestYeild{public static void main(String[] args){Thread3 t1 = new Thread3("t1");//同一个线程类是可以new多个线程对象的Thread3 t2 = new Thread3("t2");t1.start();t2.start();}}class Thread3 extends Thread{Thread3(String s){super(s);}public void run(){for(int i=0;i<100;i++){            System.out.println("i name"+ i+ getName());if(i%10==0){yield();}}}}

测试线程的优先级


线程优先级的代码

//测试线程的优先级public class TestPriority{public static void main(String[] args){Thread t = new Thread(new Thread1());Thread t3= new Thread(new Thread2());t.setPriority(Thread.NORM_PRIORITY+3);t.start();t3.start();}}class Thread1 implements Runnable{public void run(){for(int i = 0;i<100;i++){System.out.println("thread1 : "+i);}}}class Thread2 implements Runnable{public void run(){for(int i =0;i<100;i++){System.out.println("thread2: "+i);}}}

正确的停止线程的方式:

//正确的停止线程的方式,最好不用stop方法,太简单粗暴,线程来不及关闭一个窗口就直接stoppublic class StopThread{public static void main(String[] args){RunTest r = new RunTest();Thread t = new Thread(r);t.start();for(int i =0;i<100;i++){System.out.println("----"+i);}r.shutDown();}}class RunTest implements Runnable{boolean flag = true;public void run(){while(flag){for(int i =0;i<100;i++){System.out.println(i);}}}public void shutDown(){flag = false;}}

线程互斥同步方式:

若想避免多个线程同时访问一个资源,就使用synchronized关键字来对对象进行锁定,不让其他的线程访问,直到该线程访问结束

//测试线程同步public class TestSync implements Runnable{TestTimer timer = new TestTimer();public static void main(String[] args){TestSync t = new TestSync();Thread t1 = new Thread(t);Thread t2 = new Thread(t);t1.setName("t1");t2.setName("t2");t1.start();t2.start();}public void run(){timer.add(Thread.currentThread().getName());}}class TestTimer{private static int num = 0;public /*synchronized*/ void add(String name){//也可以在方法前加上关键字synchronized来对该对象进行锁定synchronized(this){  //通过synchronized关键字锁定当前对象,这样该代码资源会被锁定,在执行的过程中不被其他的线程所干扰num++;try{Thread.sleep(1);}catch (InterruptedException e){}System.out.println(name+"是第"+num+"个人访问的");}}}





线程死锁的代码:(有问题)

//测试线程死锁的例子public class TestDeadLine implements Runnable{int flag =1;Object o1 = new Object();Object o2 = new Object();public void run(){System.out.println("flag:"+flag);if(flag == 1){synchronized(o1){try{Thread.sleep(500);}catch (InterruptedException e){e.printStackTrace();}synchronized(o2){System.out.println(0);}}}if(flag == 0){synchronized(o2){try{Thread.sleep(500);}catch (InterruptedException e){e.printStackTrace();}synchronized(o1){System.out.println(1);}}}}public static void main(String[] args){TestDeadLine tdl1= new TestDeadLine();TestDeadLine tdl2 = new TestDeadLine();tdl1.flag=1;tdl2.flag=0;Thread t = new Thread(tdl1);Thread t2 = new Thread(tdl2);t.start();t2.start();}}

加锁例子:

//面试题:当m1在执行的时候,m2能够被执行吗   :结果是能够执行m2方法,,原因是因为m1方法使用了加锁,当前的对象不能访问m1方法,但是可以允许其他的对象访问没有加锁的代码段public class TT implements Runnable{int b =100;public synchronized void m1()throws Exception{b=1000;Thread.sleep(500);System.out.println("b="+b);}public void m2(){System.out.println(b);}public void run(){try{m1();}catch (Exception e){e.printStackTrace();}}public static void main(String[] args){TT tt= new TT();Thread t = new Thread(tt);t.start();Thread.sleep(1000);tt.m2();//若输出结果b是100的话则在m1()执行的过程中是不能执行m2方法的,//因为m1方法中将b修改为1000,但是m1还没有解锁,所以m2只能看到100;}}

生产者和消费者经典问题的代码

public class ProduceConsumer{public static void main(String[] args){SyncStack ss = new SyncStack();Producer p = new Producer(ss);Consumer c = new Consumer(ss);new Thread(p).start();new Thread(c).start();}}class WoTou  //定义馒头类{ int id; WoTou(int id){ this.id = id; } public String toString(){ return "WoTou:"+id; }}class SyncStack  //定义装馒头的筐子{int index = 0;WoTou[] arrWT =  new WoTou[6];public synchronized void push(WoTou wt){while(index == arrWT.length){try{this.wait();//让当前正在访问该对象的线程等待(该方法必须是synchronized方法,才能使用wait方法)}catch (InterruptedException e){e.printStackTrace();}}this.notify();//叫醒一个当前对象中等待的线程的方法,一般是和wait配套使用(不是叫醒这个push方法,而是叫醒pop方法)arrWT[index] = wt;index++;}public synchronized WoTou pop(){while(index ==0){  try{this.wait();//让当前正在访问该对象的线程等待(该方法必须是synchronized方法,才能使用wait方法)}catch (InterruptedException e){e.printStackTrace();}}this.notify();//若有多个生产者在生产者,这里就用notifyAll();index--;return arrWT[index];}}class Producer implements Runnable{SyncStack ss = null;Producer(SyncStack ss){this.ss = ss;}public void run(){for (int i =0;i<20 ;i++ ){WoTou wt =  new WoTou(i);ss.push(wt);System.out.println("生产了:"+wt);try{Thread.sleep(1000);}catch (InterruptedException e ){e.printStackTrace();}}}}class Consumer implements Runnable{SyncStack ss = null;public Consumer(SyncStack ss){this.ss = ss;}public void run(){for (int i=0;i<20 ;i++ ){WoTou wt =  ss.pop();System.out.println("消费了:"+wt);try{Thread.sleep(1000);}catch (InterruptedException e ){e.printStackTrace();}System.out.println(wt);}}}
sleep()方法和wait()方法的区别。

第一:sleep()方法是Thread类中的方法,wait()方法是object中的方法

第二:sleep()方法时别的线程不可以访问锁定的对象,wait()方法的时候别的线程可以访问锁定对象,调用wait方法的时候必须要锁定该对象

0 0
原创粉丝点击