首页 > 代码库 > java学习-线程
java学习-线程
由于自己最近接手一个项目,构思过程中,线程可能会用的较多,所以今天翻出来把线程这块好好复习一下,以下是一点学习总结。分享写的比较拙略,只为自己笔记。为自己以后存储参考资源而已。
pass:(被重写的方法不能跑一个比父类更大的异常)
创建于一个继承thread的子类:
1 class testThread extends Thread{ 2 public void Run(){//新建一个线程里的run方法,实现此子线程需要完成的功能 3 for(int i = 0;i < 100;i++){ 4 Thread.currentThread().sleep(1000); 5 System.out.println(Thread.currentThread().getName()+":"+i); 6 } 7 } 8 } 9 public class TestThread{10 static void main(String arg[]){11 testThread sT1 = new testThread();12 testThread sT2 = new testThread();//创建一个子类的对象13 sT1.setName("线程1:");14 sT1.setpriority(Thread.MAX.PRIORITY);15 sT1.start();16 sT2.setName("线程2:");17 sT2.start();18 //调用线程的start方法,启动此线程,调用相应的run方法,19 //一个线程只能执行一次start,具体请见jdk手册。20 //如果此处启用的是run方法,则不是双线程。必须是start方法。21 Thread.currentThread().setName("子线程:");22 for(int i = 0;i < 100;i++){23 System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority()+":"i);24 /*if(i % 10 == 0){25 Thread.currentThread().yield();26 27 }*/28 /*if(i % 10 ==0){29 try{30 sT1.join();31 }catch(InterruptedException e){32 e.printStackTrace();33 }34 }*/35 }36 System.out.println(sT1.isAlive());/*返回FALSE*/37 }38 }
Thread常用方法:
1.start() 启动线程并执行相应的run方法。
2.run() 子线程要执行的代码放入其中,一般都是被重写。
3.currentThread() 静态的,调取当前的线程
4.getName() 获取当前线程的名字
5.setName() 设置子线程的名字
6.yield() 线程释放当前cpu的执行权
7.join() 在a线程中调用b线程的join方法,表示,当执行到此方法,a线程停止,直至b线程全部结束,a线程才继续执行
8.isAlive() 判断当前线程是否还存活
9.sleep(long l) 显示的当前线程睡眠1毫秒
10.设置线程的优先级:getpriority() 返回线程优先级;setpriority(int newpriority)改变线程的优先级
1 /* 2 创建两个子线程,让其中一个输出1-100之间的偶数,另一个输出1-100之间的奇数 3 */ 4 class SubThread1 extends Thread{ 5 public void Run(){ 6 for (int i = 1; i < 100;i++){ 7 if(i % 2 == 0){ 8 System.out.println(Thread.currentThread().getName()+":"+i); 9 }10 }11 }12 }13 class SubThread2 extends Thread{14 public void Run(){15 for (int i = 1; i < 100;i++){16 if(i % 2 != 0){17 System.out.println(Thread.currentThread().getName()+":"+i);18 }19 }20 }21 }22 public class TestThread{23 public static void main(String[] args) {24 SubThread sT1 = new SubThread1();25 SubThread sT2 = new SubThread();26 //sT1.start();27 //sT2.start();28 //继承于Thread类的匿名对象29 new Thread(){30 public void Run(){31 for (int i = 1; i < 100;i++){32 if(i % 2 != 0){33 System.out.println(Thread.currentThread().getName()+":"+i);34 }35 }36 }}.start();37 new Thread(){38 public void Run(){39 for (int i = 1; i < 100;i++){40 if(i % 2 != 0){41 System.out.println(Thread.currentThread().getName()+":"+i);42 }43 }44 }}.start();45 46 }47 }
1 /*模拟火车站首售票窗口,开启三个窗口售票.总票数为100张*/ 2 class Window extends Thread{ 3 static int tickets = 100;//声明为固定变量实现公用,限制只有一百张,但声明周期很长 4 public void Run(){ 5 while(true){ 6 if(tickets > 0){ 7 System.out.println(Thread.currentThread().getName()+"售票.票号为:"+ tickets--); 8 }else{ 9 break;//退出10 }11 }12 }13 }14 public class TestWindow{15 16 }17 18 public static void main(String[] args) {19 Window W1 = new Window();20 Window W2 = new Window();21 Window W3 = new Window();22 23 W1.setName("窗口1:");24 W2.setName("窗口2:");25 W3.setName("窗口3:");26 27 W1.start();28 W2.start();29 w3.start();30 }
第二种方式-实现:
//1.创建一个实现了runable的类 class PrintNum1 implements Runable{ public void run(){//实现接口的抽象方法 for (int i = 1; i < 100;i++){ if(i % 2 != 0){ System.out.println(Thread.currentThread().getName()+":"+i); } } }}public class TestWindow1{ public static void main(String[] args) { //2.创建一个runable接口的实现对象 PrintNum1 p = new PrintNum1(); //要想启动一个多线程,必须调用start方法 //3.将此对象作为形参传递给Thread类的构造器中,创建Thread类的对象,此对象即为一个线程。 Thread T1 = new Thread(p);//构造一个Thread对象 T1.start(); //启动线程,执行Thread对象生成时构造器形参的对象的Run方法 //4.在创建一个线程 Thread T2 = new Thread(p);//构造一个Thread对象 T2.start(); } }
实现的方式实现多窗口售票 存在线程的安全问题
为何会出现程序的安全问题?
由于一个线程在操作共享数据的执行过程中未执行完的情况下,另外的线程参与进来,导致共享数据存在安全问题
如何解决?
必须让一个操作共享数据完毕之后,其他线程才有机会共享数据的操作。
java如何实现线程安全?
线程的同步:1.同步代码块 synchronized(同步监视器){
需要同步的代码块(操作数据共享的代码)
}
共享数据:多个线程共同操作的一个数据
同步监视器:由任何一个类的对象来充当,那个线程获取此监视器,谁就执行大括号里面的代码 俗称:锁
在实现的方式中考虑同步的话可以考虑this来充当锁,但在继承当中需要慎重.
1 class Window1 implements Thread{ 2 int ticket = 100;//共享数据 3 static Object object = new Object(); 4 public void run(){ 5 //Object object = new Object();不能在此处写,这样会导致引发三次局部变量 6 while(true){ 7 synchronized(object){//此处可以为this,代表当前的对象W1 8 if(tickets > 0){ 9 try{//这个地方会出现重票和错票10 11 Thread.currentThread().sleep(10);//让其休眠10毫秒12 }catch(InterruptedException e){13 e.printStackTrace();14 }15 System.out.println(Thread.currentThread().getName()+"售票.票号为:"+ tickets--);16 }else{17 break;//退出18 }19 }20 }21 }22 }23 public class TestWindow1{24 public static void main(String[] args) {25 Window1 W1 = new Window1();26 Thread t1 = new Thread(W1);27 Thread t2 = new Thread(W1);28 /*只new了一个w对象,三个线程共享*/29 t1.setName("窗口1:");30 t2.setName("窗口2:");31 32 t1.start();33 //共享同一个W对像34 35 t2.start();36 37 }38 39 }
1 /*实现改进版售票器*/ 2 class Window1 implements Thread{ 3 int ticket = 100; 4 public void run(){ 5 while(true){ 6 if(tickets > 0){ 7 /*try{//这个地方会出现重票和错票 8 9 Thread.currentThread().sleep(10);//让其休眠10毫秒10 }catch(InterruptedException e){11 e.printStackTrace();12 }*/13 System.out.println(Thread.currentThread().getName()+"售票.票号为:"+ tickets--);14 }else{15 break;//退出16 }17 }18 }19 }20 public class TestWindow1{21 public static void main(String[] args) {22 Window1 W1 = new Window1();23 Thread t1 = new Thread(W1);24 Thread t2 = new Thread(W1);25 /*只new了一个w对象,三个线程共享*/26 t1.setName("窗口1:");27 t2.setName("窗口2:");28 29 t1.start();30 //共享同一个W对像31 32 t2.start();33 34 }
同步方法
将操作共享数据的方法声明为synchronized,
即此方法为同步方法,能够保证当其中一个线程执行此方法时,
其他线程在外等待直到此线程执行完此方法
>同步方法的锁是当前对象:this
线程的弊端:同一个时间只有一个线程访问共享数据,效率变低了。
1 /*实现改进版售票器*/ 2 class Window1 implements Thread{ 3 int ticket = 100; 4 public void run(){ 5 while(true){ 6 show(); 7 8 } 9 }10 public synchronized void show(){11 12 if(tickets > 0){13 try{//这个地方会出现重票和错票14 Thread.currentThread().sleep(10);//让其休眠10毫秒15 }catch(InterruptedException e){16 e.printStackTrace();17 }18 System.out.println(Thread.currentThread().getName()+"售票.票号为:"+ tickets--);19 }else{20 break;//退出21 22 }23 }24 }25 public class TestWindow1{26 public static void main(String[] args) {27 Window1 W1 = new Window1();28 Thread t1 = new Thread(W1);29 Thread t2 = new Thread(W1);30 /*只new了一个w对象,三个线程共享*/31 t1.setName("窗口1:");32 t2.setName("窗口2:");33 34 t1.start();35 //共享同一个W对像36 37 t2.start();38 39 }
1 /*继承实现同步方法*/ 2 class Window extends Thread{ 3 static int tickets = 100;//声明为固定变量实现公用,限制只有一百张,但声明周期很长 4 static Object o = new Object(); 5 public void Run(){ 6 while(true){ 7 synchronized(o){ 8 if(tickets > 0){ 9 System.out.println(Thread.currentThread().getName()+"售票.票号为:"+ tickets--);10 }else{11 break;//退出12 }13 }14 }15 }16 }17 public class TestWindow{18 public static void main(String[] args) {19 Window W1 = new Window();20 Window W2 = new Window();21 Window W3 = new Window();22 23 W1.setName("窗口1:");24 W2.setName("窗口2:");25 W3.setName("窗口3:");26 27 W1.start();28 W2.start();29 w3.start();30 }31 }
/*懒汉模式-单例模式sleep()和yield()不会释放锁的,static方法里面锁不能写this,使用当前类本身充当*/class Singleton{ private Singleton(){ } private static Singleton instance = null; public static Singleton getInstance(){ if(instance == null){ synchronized(Singleton.class){ if(instance == null){ instance = new Singleton(); } } } return instance; } } public class TestSingleton{ public static void main(String[] args) { Singleton s1 = new Singleton.getInstance(); Singleton s2 = new Singleton.getInstance(); System.out.println(s1 == s2);//判断两个对象相等,只能用== } }
1 /*银行存钱问题 2 */ 3 class Count{ 4 double balance;//余额 5 public Account(){ 6 7 } 8 public synchronized void despoit(double amt){//存钱 9 notify();//实现二者交替打印10 balance += amt;11 try{12 Thread.currentThread().sleep(10);13 }14 catch(InterruptedException e){15 e.printStackTrace();16 }17 System.out.println(Thread.currentThread().getName()+":"+balance);18 wait();19 }20 21 }22 class Customer extends Thread{23 Account account;24 public Customer(Account account){25 this.account = account;26 }27 public void run(){28 for(int i = 0;i<3;i++){29 account.despoit(1000);30 }31 }32 }33 public class TestAccount{34 public static void main(String[] args) {35 Account acct =new Account();36 Customer c1 = new Customer(acct);37 Customer c2 = new Customer(acct);38 Customer c3 = new Customer(acct);39 40 c1.setName("1");41 c2.setName("2");42 c3.setName("3");43 44 c1.start();45 c2.start();46 c3.start();47 }48 }
1 /*死锁问题--处理线程同步时容易出现 2 不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的资源,就形成了线程的死锁*/ 3 public class TestDeadLock{ 4 static StringBuffer sb1 = new StringBuffer(); 5 static StringBuffer sb2 = new StringBuffer(); 6 7 public static void main(String[] args) { 8 new Thread(){ 9 public void run(){10 synchronized(sb1){11 try{12 Thread.currentThread().sleep(10);13 }14 catch(InterruptedException e){15 e.printStackTrace();16 }17 sb1.append("A");18 synchronized(sb2){19 sb2.append("B");20 System.out.println(sb1);21 System.out.println(sb2);22 }23 }24 }25 }.start();26 27 new Thread(){28 public void run(){29 synchronized(sb1){30 try{31 Thread.currentThread().sleep(10);32 }33 catch(InterruptedException e){34 e.printStackTrace();35 }36 sb1.append("C");37 synchronized(sb2){38 sb2.append("D");39 System.out.println(sb1);40 System.out.println(sb2);41 }42 }43 }44 }.start();45 }46 }
/*Deadlock.java*/class A{ public synchronized void foo(B b){ System.out.println("当前线程名:"+Thread.currentThread().getName()+"进入了A实例的foo方法"); try{ Thread.sleep(200) }catch(InterruptedException e){ e.printStackTrace(); } System.out.println("当前线程名:"+Thread.currentThread().getName()+"企图调用b的last方法"); } public synchronized void Last(){ System.out.println("进入了A的last方发出内部"); }}class B{ public synchronized void bar(A a){ System.out.println("当前线程名:"+Thread.currentThread().getName()+"进入了B实例的bar方法");try{ Thread.sleep(200) }catch(InterruptedException e){ e.printStackTrace(); } System.out.println("当前线程名:"+Thread.currentThread().getName()+"企图调用A的last方法"); } public synchronized void Last(){ System.out.println("进入了B的last方发出内部"); }}public class Deadlock implements Runable{ A a = new A(); B b = new B(); public void init(){ Thread.currentThread.setName("主线程"); //调用a对象的foo方法 a.foo(b); System.out.println("进入了主线程之后"); } public void run(){ Thread.currentThread.setName("副线程"); //调用b对象的bar方法 b.bar(a); System.out.println("进入了副线程之后"); } public static void main(String[] args) { Deadlock d1 = new Deadlock(); new Thread(d1).start();//启动run方法 d1.init(); }}
线程通信:
1.wait()方法:令当前线程挂起并放弃CPU,同步资源,使别的线程可访问并修改资源,而当前线程排队等候再次对资源的访问
2.notify()方法:唤醒正在排队等待同步资源的线程中优先级最高的
3.notifyAll()方法:唤醒正在等待资源的所有线程结束等待
java.lang.Object提供的这三个方法只有在synchronized方法中或synchronized代码块中才能使用,否则会报错
线程通信:
1 打印1-100,线程1,线程2交替打印*/ 2 class PrintNum implements Runable{ 3 int num = 1; 4 public void run(){ 5 6 while(true){ 7 synchronized(this){ 8 notify(); 9 if(num<100){10 try{Thread.currentThread().sleep(10);11 }catch(InterruptedException e){12 e.printStackTrace();13 }14 System.out.println(Thread.currentThread().getName()+":"+num);15 num++;16 }else{17 break;18 }19 wait();20 }21 }22 }23 }24 25 public class TestCommunication{26 public static void main(String[] args) {27 PrintNum p = new PrintNum();28 Thread t1 = new Thread(p);29 Thread t2 = new Thread(p);30 31 t1.setName("甲");32 t1.setName("乙");33 34 t1.start();35 t2.start();36 }37 38 }
生产者、消费者问题
多线程:消费者/生产者
共享数据:产品数量
1 class Clerk{//店员 2 int product; 3 4 public synchronized void addProduct(){//生产产品 5 if(product >= 20){ 6 wait(); 7 }else{ 8 product++; 9 System.out.println(Thread.currentThread().getName()+":生产了第"+ product +"个");10 notifyall();11 }12 13 }14 public synchronized void consumeProduct(){//消费产品15 if(product <= 0){16 wait();17 }else{18 System.out.println(Thread.currentThread().getName()+"消费了第"+product +"个");19 product--;20 notifyall();21 }22 }23 }24 class Producer implements Thread{//生产者25 Clerk clerk;26 27 public Producer(Clerk clerk){28 this.clerk = clerk;29 }30 public void run(){31 System.out.println("生产者开始生产产品。");32 while(true){33 try{ 34 Thread.currentThread().sleep(10);35 }catch(InterruptedException e)36 {37 e.printStackTrace();38 }39 clerk.addProduct();40 }41 }42 43 }44 class Consumer implements Runable{//消费者45 Clerk clerk;46 public Consumer(Clerk clerk){47 this.clerk = clerk;48 }49 public void run(){50 System.out.println("消费者开始消费产品。");51 while(true){52 try{53 Thread.currentThread().sleep(10);54 }catch(InterruptedException e) 55 {56 e.printStackTrace();57 }58 clerk.consumeProduct();59 }60 }61 }
java学习-线程