标签:lan 机器 共享 就是 取消 导致 睡眠 中断 相互
本章关注复杂软件系统的构造。 本章关注复杂软件系统的构造。 这里的“复杂”包括三方面: 这里的“复杂”包括三方面: (1)多线程序 (2)分布式程序 (3) GUI 程序
【并发(concurrency)】
【共享内存】
【信息传递】
并发模型 | 通信机制 | 同步机制 |
共享内存 |
线程之间共享程序的公共状态,线程之间通过写-读内存中的公共状态来隐式进行通信。 |
同步是显式进行的。程序员必须显式指定某个方法或某段代码需要在线程之间互斥执行。 |
消息传递 |
线程之间没有公共状态,线程之间必须通过明确的发送消息来显式进行通信。 |
由于消息的发送必须在消息的接收之前,因此同步是隐式进行的。 |
【方式1:继承Thread类】
1 //1):定义一个类A继承于java.lang.Thread类. 2 class MusicThread extends Thread{ 3 //2):在A类中覆盖Thread类中的run方法. 4 public void run() { 5 //3):在run方法中编写需要执行的操作 6 for(int i = 0; i < 50; i ++){ 7 System.out.println("播放音乐"+i); 8 } 9 } 10 } 11 12 public class ExtendsThreadDemo { 13 public static void main(String[] args) { 14 15 for(int j = 0; j < 50; j ++){ 16 System.out.println("运行游戏"+j); 17 if(j == 10){ 18 //4):在main方法(线程)中,创建线程对象,并启动线程. 19 MusicThread music = new MusicThread(); 20 music.start(); 21 } 22 } 23 } 25 }
1 //1):定义一个类A实现于java.lang.Runnable接口,注意A类不是线程类. 2 class MusicImplements implements Runnable{ 3 //2):在A类中覆盖Runnable接口中的run方法. 4 public void run() { 5 //3):在run方法中编写需要执行的操作 6 for(int i = 0; i < 50; i ++){ 7 System.out.println("播放音乐"+i); 8 } 9 10 } 11 } 12 13 public class ImplementsRunnableDemo { 14 public static void main(String[] args) { 15 for(int j = 0; j < 50; j ++){ 16 System.out.println("运行游戏"+j); 17 if(j == 10){ 18 //4):在main方法(线程)中,创建线程对象,并启动线程 19 MusicImplements mi = new MusicImplements(); 20 Thread t = new Thread(mi); 21 t.start(); 22 } 23 } 24 }
Thread newThread = new Thread(MyRunnable()); newThread.run(); //should be start();
起初并不会感觉到有什么不妥,因为 run()方法的确如你所愿的被调用了。但是,事实上,run()方法并非是由刚创建的新线程所执行的,而是被创建新线程的当前线程所执行了。也就是被执行上面两行代码的线程所执行的。想要让创建的新线程执行 run()方法,必须调用新线程的 start 方法。
【时间分片】
【交错执行】
顾名思义,就是说在线程运行的过程中,多个线程同时运行相互交错。而且,由于线程运行一般不是连续的,那么就会导致线程间的交错。可以说,所有线程安全问题的本质都是线程交错的问题。
【竞争条件】
竞争是发生在线程交错的基础上的。当多个线程对同一对象进行读写访问时,就可能会导致竞争的问题。程序中可能出现的一种问题就是,读写数据发生了不同步。例如,我要用一个数据,在该数据修改还没写回内存中时就读取出来了,那么就会导致程序出现问题。
程序运行时有一种情况,就是程序如果要正确运行,必须保证A线程在B线程之前完成(正确性意味着程序运行满足其规约)。当发生这种情况时,就可以说A与B发生竞争关系。
【Thread.sleep】
在线程中允许一个线程进行暂时的休眠,直接使用Thread.sleep()方法即可。
public static void sleep(long milis,int nanos) throws InterruptedException
首先,static,说明可以由Thread类名称调用,其次throws表示如果有异常要在调用此方法处处理异常。
所以sleep()方法要有InterruptedException 异常处理,而且sleep()调用方法通常为Thread.sleep(500) ;形式。
【Thread.interrupt】
package Thread1; class MyThread implements Runnable{ // 实现Runnable接口 public void run(){ // 覆写run()方法 System.out.println("1、进入run()方法") ; try{ Thread.sleep(10000) ; // 线程休眠10秒 System.out.println("2、已经完成了休眠") ; }catch(InterruptedException e){ System.out.println("3、休眠被终止") ; return ; // 返回调用处 } System.out.println("4、run()方法正常结束") ; } }; public class demo1{ public static void main(String args[]){ MyThread mt = new MyThread() ; // 实例化Runnable子类对象 Thread t = new Thread(mt,"线程"); // 实例化Thread对象 t.start() ; // 启动线程 try{ Thread.sleep(2000) ; // 线程休眠2秒 }catch(InterruptedException e){ System.out.println("3、休眠被终止") ; } t.interrupt() ; // 中断线程执行 } };
运行结果:
1、进入run()方法 3、休眠被终止
【Confinement 限制数据共享】
public class Factorial { /** * Computes n! and prints it on standard output. * @param n must be >= 0 */ private static void computeFact(final int n) { BigInteger result = new BigInteger("1"); for (int i = 1; i <= n; ++i) { System.out.println("working on fact " + n); result = result.multiply(new BigInteger(String.valueOf(i))); } System.out.println("fact(" + n + ") = " + result); } public static void main(String[] args) { new Thread(new Runnable() { // create a thread using an public void run() { // anonymous Runnable computeFact(99); } }).start(); computeFact(100); } }
解释:主函数开启了两个线程,调用的是相同函数。因为线程共享局部变量的类型,但每个函数调用有不同的栈,因此有不同的i,n,result。由于每个函数都有自己的局部变量,那么每个函数就可以独立运行,更新它们自己的函数值,线程之间不影响结果。
【Immutability 共享不可变数据】
不可变数据类型,指那些在整个程序运行过程中,指向内存的引用是一直不变的,通常使用final来修饰。不可变数据类型通常来讲是线程安全的,但也可能发生意外。
但是,程序在运行过程中,有时为了优化程序结构,默默地将这个引用更改了。此时,客户端程序员是不知道它被更改了,对于客户端而言,这个引用还是不可变的,但其实已经被悄悄更改了。这时就会发生一些线程安全问题。
解决方案就是给这些不可变数据类型再增加一些限制:
这样就可以保证线程的安全了。
【Threadsafe data type(共享线程安全的可变数据)】
private static Map<Integer,Boolean> cache = Collections.synchronizedMap(new HashMap<>()); public static <T> Collection<T> synchronizedCollection(Collection<T> c); public static <T> Set<T> synchronizedSet(Set<T> s); public static <T> List<T> synchronizedList(List<T> list); public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m); public static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s); public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m);
List<Type> c = Collections.synchronizedList(new ArrayList<Type>()); synchronized(c) { // to be introduced later (the 4-th threadsafe way) for (Type e : c) foo(e); }
如果在isEmpty和get中间,将元素移除,也就产生了竞争。
前三种策略的核心思想:避免共享 --> 即使共享,也只能读/不可写(immutable) -->即使可写(mutable),共享的可写数据应自己具备在多线程之间协调的能力,即“使用线程安全的mutable ADT”
【Synchronization 同步与锁】
public synchronized void save(){}
synchronized(object){ }
标签:lan 机器 共享 就是 取消 导致 睡眠 中断 相互
原文地址:https://www.cnblogs.com/hithongming/p/9204473.html