文档章节

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
粉丝 38
博文 179
码字总数 106191
作品 0
深圳
架构师
synchronized与ThreadLocal

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

bigYuan
2013/07/18
0
2
Java面试:投行的15个多线程和并发面试题

本文由ImportNew -一杯哈希不加盐 翻译自dzone。欢迎加入翻译小组。转载请见文末要求。 多线程和并发问题已成为各种 Java 面试中必不可少的一部分。如果你准备参加投行的 Java 开发岗位面试,...

ImportNew
08/23
0
0
【转】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

没有更多内容

加载失败,请刷新页面

加载更多

6. Python3源码—List对象

6.1. List对象 List对象是“变长对象”。 6.1.1. Python中的创建 Python中List对象最重要的创建方法为PyList_New,如下Python语句最终会调用到PyList_New: test = [1, 2, 3, 4, 5] 6.1.2. ...

Mr_zebra
17分钟前
1
0
nginx屏蔽指定接口(URL)

Step1:需求 web平台上线后,需要屏蔽某个服务接口,但又不想重新上线,可以采用nginx屏蔽指定平台接口的办法 Step2:具体操作 location /dist/views/landing/UNIQUE_BEACON_URL { re...

Linux_Anna
25分钟前
2
0
tomcat高并发配置调优

作者:Joker-pan 原文:https://blog.csdn.net/u011622226/article/details/72510385?utm_source=copy --------------------- tomcat 解压就使用的,配置都没动过,肯定不能支持高并发了; ...

imbiao
43分钟前
4
0
mysql 联结,级联查询总结区分

其实我对 数据库的级联或者联结查询一直都是会用,项目能查询出来自己想要的结果即可。 毕竟SQL使用复杂的查询毕竟比较少,而且不难使用。 至于区分他们,我还真的有点模糊。 在看 《SQL必知...

之渊
今天
3
0
区块链入门教程分享区块链POW证明代码实现demo

兄弟连区块链入门教程分享区块链POW证明代码实现demo 这里强调一下区块链的协议分层 应用层 合约层 激励机制 共识层 网络层 数据层 上 一篇主要实现了区块链的 数据层,数据层主...

兄弟连区块链入门教程
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部