第三讲
线程的互斥与同步通信
两个线程访问同一对象(取并进行修改)
多线程同时访问一个数据(银行汇款问题)balance余额
线程安全问题,可以用银行转账解释
(
1.内部类不能访问局部变量,要想访问就需要加final
2.静态方法不能new内部类的实例对象,内部类可以访问外部类的成员变量
)
public class TraditionalThreadSynchronized{
public static void main(String[] args){
new TraditonalThreadSynchronized().init();
}
private void init(){
Outputer outputer = new OutPuter();
new Thread(new Runnable(){
@Override
public void run() {
try{
Thread.sleep(10);
}
catch(InterruptedException e){
e.printStackTrace();
}
outputer.output(“lihuoming”);
}
}).start();
new Thread(new Runnable(){
@Override
public void run() {
try{
Thread.sleep(10);
}
catch(InterruptedException e){
e.printStackTrace();
}
outputer.output(“zhangxiaoxiang”);
}
}).start();
}
class Outputer{
String xxx = “”;
public void output(String name){
int len = name.length();
synchronized(xxx){
for (int i = 0; i < len; i++){
System.out.println(name.charAt(i));
}
System.out.println();
}
}
}
}
会出现线程问题,解决问题要实现原子行。(比如茅坑问题,只能一个人进去)
把你要保护的代码,用关键词synchronized扩起来,有一把门闩,任何对象都可以当作门闩。
每个线程进来执行的时候需要获取门闩,互斥要用一个对象.
用xxx有点多此一举,可以用synchronized(this),实现互斥
保护方法内的所用代码,直接在代码前面加上synchronized
public void output(String name)–à public synchronized void output(String name)
静态方法的同步synchronized(Output.class)
public synchronized void output2(String name)
以上是线程互斥。
第四讲
下面讲线程同步
看一道面试题:
子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次,接着再回到主线程又循环100次,如此循环50次。写出程序
public class TraditionalThreadCommunication{
public static void main(String[] args){
new Thread(
new Runnable(){
@Override
public void run(){
for (int i = 1; i <=50; i++){
synchronized(TraditionalThreadCommunication.class){
for (int j = 1; j < = 10; j++){
System.out.println(“sub thread sequence of ” + j + “ look of ” + i);
}
}
}
}
}).start();
for (int i = 1; i <=50; i++){
synchronized(TraditionalThreadCommunication.class){
for (int j = 1; j < = 100; j++){
System.out.println(“main thread sequence of ” + j + “ look of ” + i);
}
}
}
}
//第二种方式
final Business business = new Business ();
public static void main2(String[] args){
new Thread(
new Runnable(){
@Override
public void run(){
for (int i = 1; i <=50; i++){
business.sub(i);
}
}
}).start();
for (int i = 1; i <=50; i++){
business.main(i);
}
}
}
第一种基本实现,实现方式不好,不是你执行一下我执行一下。
把相关联的方法放到一个类里面,好维护好更改(高内聚)
内部类
class Business{
private Boolean bShouldSub = true;
public synchronized void sub(int i){
if (!bShouldSub) {
this.wait();
}
for (int j = 1; j < = 10; j++){
System.out.println(“sub thread sequence of ” + j + “ look of ” + i);
}
bShouldSub = false;
this.notify();
}
public synchronized void main(int i){
if (!bShouldSub){
this.wait();
}
for (int j = 1; j < = 100; j++){
System.out.println(“main thread sequence of ” + j + “ look of ” + i);
}
bShouldSub = true;
this.notify();
}
}
经验:要用到共同数据(包括同步锁)或共同算法的若干个方法应该归在同一个类身上,这种设计正好体现了高内聚和程序的健壮性
锁是上在代表要操作的资源的类的内部方法中(如Business),而不是线程代码中
把if(bShouldSub)可以改成while(bShould), 可以解决伪唤醒
第5讲
线程范围内共享数据(底层框架经常用到)
public class ThreadScopeShareData{
private static int data = 0;
public static void main(String[] args){
for (int i = 0; i < 2; i++){
new Thread(new Runnable(){
@Override
public void run(){
data = new Random().nexeInt();
System.out.println(Thread.currentThread().getName() + “has put data : ” + data);
threadData.put(thread.currentThread(), data);
new A().get();
new B().get();
}
}).start();
}
}
static class A{
public void get(){
System.out.println(“A from ” + Thread.currentThread().getName() + “get data : ” + data);
}
}
static class B{
public void get(){
System.out.println(“A from ” + Thread.currentThread().getName() + “get data : ” + data);
}
}
}
//两个线程现在拿到的都是一样的,同一份
public class ThreadScopeShareData{
private static int data = 0;
private static map<Thread, Integer> threadData = new HashMap<Thread, Interger>();
public static void main(String[] args){
for (int i = 0; i < 2; i++){
new Thread(new Runnable(){
@Override
public void run(){
data = new Random().nexeInt();
System.out.println(Thread.currentThread().getName() + “has put data : ” + data);
threadData.put(thread.currentThread(), data);
new A().get();
new B().get();
}
}).start();
}
}
static class A{
public void get(){
int data = threadData.get(Thread.currentThread());
System.out.println(“A from ” + Thread.currentThread().getName() + “get data : ” + data);
}
}
static class B{
public void get(){
int data = threadData.get(Thread.currentThread());
System.out.println(“A from ” + Thread.currentThread().getName() + “get data : ” + data);
}
}
}
//这时候运行两个线程获取的还是同一份
//把data = new Random().nextInt(); 改写为 int data = new Random().nextInt();就可以每个线程单独的数据
数据库连接,每个线程都是单独的,事务提交不影响其他的线程
在线程内共享,在线程外部独立
转载请注明:学时网 » 张孝祥老师-java并发编程听课笔记(二)