文档章节

JAVA多线程

wrean2013
 wrean2013
发布于 2013/09/27 10:23
字数 2575
阅读 49
收藏 0
点赞 0
评论 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
粉丝 32
博文 104
码字总数 105556
作品 0
深圳
架构师
java面试必备之ThreadLocal

按照传统的经验,如果某个对象是非线程安全的,在多线程环境下对象的访问需要采用synchronized进行同步。但是模板类并未采用线程同步机制,因为线程同步会降低系统的并发性能,此外代码同步解...

编程老司机 ⋅ 05/16 ⋅ 0

Java多线程学习(五)线程间通信知识点补充

系列文章传送门: Java多线程学习(一)Java多线程入门 Java多线程学习(二)synchronized关键字(1) java多线程学习(二)synchronized关键字(2) Java多线程学习(三)volatile关键字 Ja...

一只蜗牛呀 ⋅ 04/16 ⋅ 0

Java多线程学习(二)synchronized关键字(2)

系列文章传送门: Java多线程学习(一)Java多线程入门 Java多线程学习(二)synchronized关键字(1) java多线程学习(二)synchronized关键字(2) Java多线程学习(三)volatile关键字 Ja...

一只蜗牛呀 ⋅ 04/16 ⋅ 0

Java多线程学习(四)等待/通知(wait/notify)机制

系列文章传送门: Java多线程学习(一)Java多线程入门 Java多线程学习(二)synchronized关键字(1) java多线程学习(二)synchronized关键字(2) Java多线程学习(三)volatile关键字 Ja...

一只蜗牛呀 ⋅ 04/16 ⋅ 0

Java编程基础知识点和技术点归纳

Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言。Java 技术具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于PC、数据中心、游戏控制台、科学超级计算机、移动电话和互...

Java小辰 ⋅ 05/23 ⋅ 0

Java面试需要准备哪些多线程并发的技术要点

一、概念 什么是线程 一个线程要执行任务,必须得有线程 一个进程(程序)的所有任务都在线程中执行的 一个线程执行任务是串行的,也就是说一个线程,同一时间内,只能执行一个任务 多线程原理 同一...

码蚁说架构 ⋅ 05/31 ⋅ 0

Java开发学习之三版本简介 java编程

  Java编程语言,在更迭迅速的互联网领域多年屹立不倒,足以得见Java这门语言旺盛的生命力,因此,会有很多想要进入互联网领域的朋友,想要学Java来转行开发。但是,所谓“隔行如隔山”,j...

老男孩Linux培训 ⋅ 06/05 ⋅ 0

InheritableThreadLocal详解

1、简介 在上一篇 ThreadLocal详解 中,我们详细介绍了ThreadLocal原理及设计,从源码层面上分析了ThreadLocal。但由于ThreadLocal设计之初就是为了绑定当前线程,如果希望当前线程的ThreadL...

沈渊 ⋅ 04/12 ⋅ 0

Java 编程之美:并发编程高级篇之一

本文来自作者 追梦 在 GitChat 上分享 「Java 编程之美:并发编程高级篇之一」 编辑 | 工藤 前言 借用 Java 并发编程实践中的话:编写正确的程序并不容易,而编写正常的并发程序就更难了。 ...

gitchat ⋅ 05/24 ⋅ 0

1、Java并发性和多线程-并发性和多线程介绍

以下内容转自http://ifeve.com/java-concurrency-thread/: 在过去单CPU时代,单任务在一个时间点只能执行单一程序。之后发展到多任务阶段,计算机能在同一时间点并行执行多任务或多进程。虽...

easonjim ⋅ 2017/06/14 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Windows下安装运行phpMyAdmin

首先确保安装了phpMyAdmin,其次要求服务器是打开的。 如果是在Windows下,建议下载安装WampServer,这是一个集成软件,集成了Apache+MySQL+PHP的开发环境,而且也自带了phpMyAdmin这个软件。...

临江仙卜算子 ⋅ 9分钟前 ⋅ 0

jdk1.8 安装及环境变量配置

1.根据jdk 的软件安装包,首先安装,jdk,

kuchawyz ⋅ 10分钟前 ⋅ 0

给Java字节码加上”翅膀“的JIT编译器

给Java字节码加上”翅膀“的JIT编译器 上面文章在介绍Java的内存模型的时候,提到过由于编译器的优化会导致重排序的问题,其中一个比较重要的点地方就是关于JIT编译器的功能。JIT的英文单词是...

九劫散仙 ⋅ 10分钟前 ⋅ 0

PCI简介(二)

1.x86处理器系统地址空间简介 1.1 CPU地址空间 CPU地址空间是指CPU所能寻址的空间大小,比如对于32位CPU来说,其所能寻址的空间大小为0~4G。这是由CPU自身的地址总线数目决定的。这段空间也被...

深山野老 ⋅ 12分钟前 ⋅ 0

spring中的InitializingBean接口

好久没更博了,真有点怀念,前段时间刚和上家公司say bye,这次进的是电商公司,今天刚开始看代码,逻辑很复杂。 今天看的注册功能,里面见到一个知识点,现在记录一下,今天看项目时见到里面...

千元机爱好者 ⋅ 13分钟前 ⋅ 0

机器学习:数据预处理之独热编码(One-Hot)

前言 ———————————————————————————————————————— 在机器学习算法中,我们经常会遇到分类特征,例如:人的性别有男女,祖国有中国,美国,法国等。 ...

NateHuang ⋅ 21分钟前 ⋅ 0

MyBatis之输入与输出(resultType、resultMap)映射

在MyBatis中,我们通过parameterType完成输入映射(指将值映射到sql语句的占位符中,值的类型与dao层响应方法的参数类型一致),通过resultType完成输出映射(从数据库中输出,通过dao层的方法查...

瑟青豆 ⋅ 22分钟前 ⋅ 0

屏蔽运营商广告劫持

在今天早上我查找知乎时再次遇到了恶心的运营商广告劫持,右下角硕大的广告直接让知乎挂掉了,我刷了五次知乎才好,之前休息的时候逛知乎也是多次加载错误,估计也是这劫持的锅,相信各位也遇...

gcudwork ⋅ 26分钟前 ⋅ 0

java web 进度条实现原理

资料路径 https://blog.csdn.net/fengsheng5210/article/details/79305026

zaolonglei ⋅ 26分钟前 ⋅ 0

命令行输出java版本与环境变量配置的不一样问题解决

问题:java10刚出来,本着好奇的心,急切的装了体验一下,然后实际项目需求还是java8,所以体验完了就把环境变量改回来了,但是出现了一个问题,命令行输出java版本与环境变量配置的不一样,...

消散了的诗意 ⋅ 29分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部