文档章节

JAVA多线程

wrean2013
 wrean2013
发布于 2013/09/27 10:23
字数 2575
阅读 49
收藏 0
1.线程的实现方式:
public class ThreadTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		//线程实现1 new一个Thread的子类。
		Thread t1 = new Thread(){
			@Override
			public void run(){
				while(true){
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getId());
				}
			}
		};
		t1.start();
		/*实现方式2(主要还是看源码):new一个Runnable的子类。
		 *  public void run() {
		 *	 if (target != null) {
		 *	    target.run();
		 *	 }
		 *  }
		 *  target!=null 执行target的run(),F3,target是private Runnable target;看黄点 找到它的赋值,最后看到在构造方法里调用init()对Runbable赋值,
		 *  看init()的引用“右键-reference-project查看项目中引用该方法的类”。
		 *  所以只要构造Runable也可以实现一种多线程。
		 *  
		 *  一般都采用第二种方式,更体现面向对象的编程,线程装在Runnbale对象中,外边在用线程Thead包装。
		 *  
		 */
		Thread  t2= new Thread(new Runnable(){
			@Override
			public void run() {
				while(true){
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getId());
				}
			}
		});
		t2.start();
		//思考如下代码的结果是什么?
		//简化成new Thread(runable.run){run}.start()
		new Thread(
				new Runnable() {
					@Override
					public void run() {
						try {
							Thread.sleep(1000);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						System.out.println("Runnable:"+Thread.currentThread().getName());						
					}
				}
			){
			@Override
			public void run() {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("Thread:"+Thread.currentThread().getName());
			};
		}.start();
		/*
		 * 用多线程会提高程序的运行效率吗? 不一定
		 * 但什么时候考虑用多线程?为什么多线程下载比单线程现在更快点?
		 * 抢占CPU,抢占带宽,抢占资源使资源最大化的时候用。
		 */
	}

}

2.定时器:

package aa.bb.cc;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Timer;
import java.util.TimerTask;

public class TimerTest {
	/**
	 * @param args
	 */
	static int i=0;
	public static void main(String[] args) {
		/*
		 * 定时器很简单:new一个Timer然后调度TimerTast
		 * 
		 */
//		new Timer().schedule(new TimerTask() {
//			@Override
//			public void run(){
//				System.out.println("bombing");
//			}
//		},10000, 3000);
//		
		new Thread(new Runnable() {
			@Override
			public void run() {
				while(true){
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(GregorianCalendar.getInstance().get(Calendar.SECOND));
				}
			}
		}).start();
		
		
		//问题:实现一个定时器,3S 6S间隔炸。
		/*
		 * 内部类中不能定义静态变量的
		 */
//		new TimerTask() {
//			@Override
//			public void run() {
//				System.out.println("bombing");
//			}
//		}
		//第一版:
//		new Timer().schedule(new TimerTask() {
//			@Override
//			public void run() {
//				System.out.println("bombing");
//				new Timer().schedule(new TimerTask() {
//					@Override
//					public void run() {
//						System.out.println("bombing");
//					}
//				},6000);
//			}
//		},3000);
		/*
		 * 提出
		 * new TimerTask() {
					@Override
					public void run() {
						System.out.println("bombing");
					}
			}
		 * 当this调用 报错。
		 * 
		 */
//		new Timer().schedule(new TimerTask() {
//		@Override
//		public void run() {
//			System.out.println("bombing");
//			new Timer().schedule(this,6000);
//		}
//	    },3000);
		//继续:
//		class MyTimerTask extends TimerTask {
//			@Override
//			public void run() {
//				System.out.println("bombing");
//				new Timer().schedule(new MyTimerTask(), 2000);
//			}
//	    }
//		new Timer().schedule(new MyTimerTask(),3000);
		
		//下来解决3S 6S交替的问题:
		/*
		 * 使用是实例变量是不行的,因为每次都新建,
		 * 所以考虑用静态变量
		 * 
		 */
		class MyTimerTask extends TimerTask {
			int interval=3000;
			@Override
			public void run() {
				if((i++)%2==0) interval=6000;
				System.out.println("bombing");
				new Timer().schedule(new MyTimerTask(), interval);
			}
	    }
		new Timer().schedule(new MyTimerTask(),3000);
		//问题:实现每天晚上3点钟发邮件!
		
		//问题:实现周一到周五每天晚上3点发邮件!使用quarz
	}

}
3.同步与互斥
多线程带来的问题就是如果多个线程同时操作一个数据对象的问题,别人经常说的例子,银行转账的例子:你的银行有1000元,一个人给你汇款200,你给别人汇款500,正常情况1000-200+500=1300,如果执行到1000-200还没有赋值的情况下(这时余额还是1000),另一个线程开始存款200存完后并赋值余额就是1200,这个时候第一个线程执行赋值余额就成了800,模拟:
public class ThreadTest3 implements Runnable{
	static int balance = 1000;
	@Override
	public void run() {
          for (int i = 0; i < 1000; i++) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
                         balance = balance+i;
			balance = balance-i;
			if(balance!=1000){
				System.err.println("err:" + balance);
				System.exit(0);
			}
			System.out.println(Thread.currentThread().getName()+":"+balance);
		}
	}
	public static void main(String[] args) {
	     ThreadTest3 tt3 = new ThreadTest3();
	     Thread t1 = new Thread(tt3);
	     Thread t2 = new Thread(tt3);
	     t1.start();
	     t2.start();
	}
}
打印出的有时不是1000,有时得多执行几次,所以出现锁,同步,互斥的概念,
提问,
(1)如果 改成
int balance = 1000;
...
是什么结果?
(2)如果改成
static int balance = 1000;
...
ThreadTest3 tt3 = new ThreadTest3();
ThreadTest3 tt4 = new ThreadTest3();
Thread t1 = new Thread(tt3);
Thread t2 = new Thread(tt4);
t1.start();
t2.start();
是什么结果?
(3)如果改成:
int balance = 1000;
...
ThreadTest3 tt3 = new ThreadTest3();
ThreadTest3 tt4 = new ThreadTest3();
Thread t1 = new Thread(tt3);
Thread t2 = new Thread(tt4);
t1.start();
t2.start();
是什么结果?
为了避免这种问题,有了同步,使某一个需要执行完全的块代码全部执行完后再让下一个线程执行这段代码,加synchronized关键字即可,类似上厕所,厕所是公共资源,不能说我在里面了另外一个人也进去了,所以需要进去之后锁上门,完事了把门开锁,钥匙给下一位。厕所是公共资源,所以要对厕所同步。
package aa.bb.cc;

public class ThreadTest4 {
	public static void main(String[] args) {
	   final ThreadTest4.Printer p=new ThreadTest4().new Printer();  
       new Thread(new Runnable() {
			@Override
			public void run() {
				while(true){
					p.print("nimade");
				}
			}
	   }).start();
       new Thread(new Runnable() {
    	   @Override
    	   public void run() {
    			while(true){
    				p.print("caonimei");
    			}
    	   }
       }).start();
	}
    class Printer{
    	public void print(String s){
    		for(int i=0;i<s.length();i++){
    			System.out.print(s.charAt(i));
    		}
    		System.out.println();
    	}
    }
}
两个线程共同使用公共资源p,会出现 nimade还没打印完就去打印caonimei或caonimei没打印完全打印nimade,print方法改为:
public void print(String s){
	synchronized ("hello") {
		for(int i=0;i<s.length();i++){
			System.out.print(s.charAt(i));
		}
		System.out.println();
	}
}
注意,几个线程要同步的代码块必须对应同一把钥匙,
public void print(String s){
	synchronized (s) {
		for(int i=0;i<s.length();i++){
			System.out.print(s.charAt(i));
		}
		System.out.println();
	}
}
是没有同步效果的,这里公共资源都是调用 print()方法对象,这个对象只有一个,所以这个对象也可以作为门栓。
public void print(String s){
	synchronized (this) {
		for(int i=0;i<s.length();i++){
			System.out.print(s.charAt(i));
		}
		System.out.println();
	}
}
可用this, 那么synchronized也可以加在方法上,一个是同步一段代码,一个是同步一个方法内的代码。
public synchronized void print(String s){
		for(int i=0;i<s.length();i++){
			System.out.print(s.charAt(i));
		}
		System.out.println();
}
要注意你要区分好同步的哪些代码块,合理用同步。
提问1:如果把p.print("caonimei");改成new ThreadTest4().new Printer().print("caonimei");把p.print("nimadede");改成new ThreadTest4().new Printer().print("nimadede");会有互斥效果吗?
提问2:如果代码改成:
package aa.bb.cc;

public class ThreadTest4 {
	public static void main(String[] args) {
	   final ThreadTest4.Printer p=new ThreadTest4().new Printer();  
       new Thread(new Runnable() {
			@Override
			public void run() {
				while(true){
					p.print("nimadede");
				}
			}
	   }).start();
       new Thread(new Runnable() {
    	   @Override
    	   public void run() {
    			while(true){
    				p.print2("caonimei");
    			}
    	   }
       }).start();
	}
    class Printer{
		public synchronized void print(String s){
			for(int i=0;i<s.length();i++){
				System.out.print(s.charAt(i));
			}
			System.out.println();
		}
		public void print2(String s){
			synchronized(this){
				for(int i=0;i<s.length();i++){
					System.out.print(s.charAt(i));
				}
				System.out.println();
			}
		}
    }
}
两个线程调用同一个对象的不同方法,一个调用print,一个调用print2,print2中的同步代码块是否和print方法互斥呢?如果把print2中的this改成"abc"呢?
第一种是互斥的,两个方法对应同一把锁,所以有互斥效果,如果改成"abc"就不互斥了。第二种的一种打印结果:
caonimei
caonimei
caonime
nimei
caonimei
caonimei
caonimei
caonimei
caon
提问3:
如果改成以下代码,会出什么结果?print2和print3是否互斥?如果不互斥怎么可以使print2和print3互斥?
package aa.bb.cc;

public class ThreadTest4 {
	public static void main(String[] args) {
		final Printer p=new Printer();  
	       new Thread(new Runnable() {
				@Override
				public void run() {
					while(true){
						p.print2("nimadede");
					}
				}
		   }).start();
	       new Thread(new Runnable() {
	    	   @Override
	    	   public void run() {
	    			while(true){
	    				p.print3("caonimei");
	    			}
	    	   }
	       }).start();
	}
	static class Printer{
		public synchronized void print(String s){
			for(int i=0;i<s.length();i++){
				System.out.print(s.charAt(i));
			}
			System.out.println();
		}
		public void print2(String s){
			synchronized("abc"){
				for(int i=0;i<s.length();i++){
					System.out.print(s.charAt(i));
				}
				System.out.println();
			}
		}
		public static synchronized void print3(String s){
			for(int i=0;i<s.length();i++){
				System.out.print(s.charAt(i));
			}
			System.out.println();
		}
    }
}

答案就是把"abc"改成Printer.class即可。
线程通信:
题目:写出子线程循环10次,主线程循环100次,然后子线程又循环10层,主线程循环100层,循环往复的下去的代码。

package bb;
/**
 * 4.线程之间 的通信
 */
public class ThreadTest {
	/*
	 *实现子线程循环10次,主线程循环20次,循环往复50次。 
	 *实现1:
	 */
	public static void main(String[] args) {
		final ThreadTest.Buesiness tb= new ThreadTest().new Buesiness();
		new Thread(new Runnable() {
			@Override
			public void run() {
				for(int j=0;j<50;j++){
					/*以ThreadTest2.class做锁不好,一般要用到共同数据(包括同步锁)或共同算法的若干个方法应该归在同一个类身上,这能体现高类聚和程序的健壮性
					 *所以有实现方式2,提出Buessiness类。
					 */
//					synchronized (ThreadTest2.class) {
//						for(int i=0;i<10;i++){
//							System.out.println("Main:" + i);
//						}
//					}
					
					tb.sub();
				}
				
			}
		}).start();
		for(int j=0;j<50;j++){
//			synchronized (ThreadTest2.class) {
//				for(int i=0;i<20;i++){
//					System.out.println("Main:" + i);
//				}
//			}
			tb.main();
		}
	}
	//实现2
	/*
	 * 设计非常重要,线程的设计最重要的有一点就是相关联的操作都放在一个类上,就是说对共同数据的操作最好独立出来一个类。便于同步和互斥,让它们自己管理自己,而不是让外边的线程去管。
	 * 两个线程中的代码片段要实现同步互斥的效果,必须对应用一把锁,锁是上在所要操作资源的内部,而不是线程代码中。
	 * 
	 * 这个类把互斥同步通信什么的都放在这个类中。如:
	 * 	new Thread(new Runnable() { //这是线程代码 操作资源不在这里管理
			@Override
			public void run() { //这是线程代码 操作资源不在这里管理
				for(int j=0;j<50;j++){
					tb.sub(); //这才是要管理的操作资源
				}
			}
		}).start();//这是线程代码 操作资源不在这里管理
	 * 这个思路很重要,要理解。
	 * 
	 * 
	 * java实现自动登录的方式
	 * 
	 */
	class Buesiness{
		boolean isSub=true;
		public synchronized void sub(){
			if(isSub){//这里的if最好改成while,更牢靠,怕存在假唤醒,别人没叫你,你自己醒来了,具体参加Object的wait的API。
				for(int i=0;i<10;i++){
					System.out.println("sub:" + i);
				}
				isSub=false;
				this.notify();
			}else{
				try {
					this.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			
		}
		public synchronized void main(){
			if(!isSub){//这里的if最好改成while,更牢靠,怕存在假唤醒,别人没叫你,你自己醒来了,具体参加Object的wait的API。
				for(int i=0;i<20;i++){
					System.out.println("main:" + i);
				}
				isSub=true;
				this.notify();//如果main线程在等记得要唤醒,唤醒后main线程在等,sub线程继续执行,sub那边写法也是一样。
			}else{
				try {
					this.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		
		
	}
}

5.线程内的共享数据
有A B两个模块取线程1的数据,同时有A B两个模块取线程2的数据,怎么让第一个A B模块取的就是线程1的数据,第二个A  B取的就是线程2的数据、让两个独立互不干涉?

TheadLocal操作当前线程变量
虚拟机死的时候给我发邮件
线程结束怎么通知到?死的时候通知我  捕获线程死的事件


多个线程共享数据

1.写个买票程序

张孝祥正在整理java就业面试题大全.doc

© 著作权归作者所有

共有 人打赏支持
wrean2013
粉丝 36
博文 180
码字总数 105556
作品 0
深圳
架构师
synchronized与ThreadLocal

synchronized是实现java的同步机制。同步机制是为了实现同步多线程对相同资源的并发访问控制。保证多线程之间的通信。 同步的主要目的是保证多线程间的数据共享。同步会带来巨大的性能开销,...

bigYuan
2013/07/18
0
2
【转】15个顶级Java多线程面试题及回答

Java 线程面试问题   在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分。如果你想获得任何股票投资银行的前台资讯职位,那么你应该准备很多关于多线程的问题。在投资银行业务...

一只死笨死笨的猪
2014/09/30
0
0
java多线程之ThreadLocal

java中的java.lang.ThreadLocal,为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序,ThreadLocal并不是一个Thread,而是Thread的局部变量。...

飞翔的兔兔
2017/07/11
0
0
15个顶级Java多线程面试题及回答

Java 线程面试问题 在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分。如果你想获得任何股票投资银行的前台资讯职位,那么你应该准备很多关于多线程的问题。在投资银行业务中多...

LCZ777
2014/05/27
0
0
浅谈Java中的ThreadLocal的多线程应用问题

什么是ThreadLocal?首先要说明的一点是ThreadLocal并不是一个Thread,而是Thread的局部变量。在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了...

小欣妹妹
2017/10/23
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

人生苦短:Python里的17个“超赞操作

人生苦短,我选Python”。那么,你真的掌握了Python吗? 1. 交换变量 有时候,当我们要交换两个变量的值时,一种常规的方法是创建一个临时变量,然后用它来进行交换。比如: # 输入 a = 5 b ...

糖宝lsh
44分钟前
4
0
咕泡-spring中常用设计模式概述

设计模式就是经验之谈,供后人借鉴,解决一些具有代表性的问题 设计模式来源于生活,反过来帮助我们更好生活 设计模式提升代码的可读性、可扩展性、维护成本、复杂业务问题 千万不要死记硬背...

职业搬砖20年
今天
2
0
day59-20180817-流利阅读笔记-待学习

假·照骗,真·社交焦虑 雪梨 2018-08-17 1.今日导读 发朋友圈之前,不少人为了展现更美好的生活状态会对照片加以“微调”,或是加个滤镜显得逼格更高,或是磨个皮瘦个脸拉个大长腿。现在,国...

aibinxiao
今天
23
0
OSChina 周五乱弹 —— 姑娘在这个节日里表白你接受么?

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @Sharon啊:完全被这个小姐姐圈粉了,学两首她的歌去哈哈 分享王贰浪的单曲《往后余生(翻自 马良)》 《往后余生(翻自 马良)》- 王贰浪 手...

小小编辑
今天
1K
16
为什么HashMap要自己实现writeObject和readObject方法?

为什么HashMap要自己实现writeObject和readObject方法? 如果你有仔细阅读过HashMap的源码,那么你一定注意过一个问题:HashMap中有两个私有方法。 private void writeObject(java.io.Objec...

DemonsI
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部