高级课——线程(下)

1,同步锁死

2,线程之间的通信

3,其他创建线程的方式


1,同步域死锁

创建三个窗口买票,总票数为60张票。按照之前的代码,会发现代码出现问题,又相同的票或者 负数出现。出现问题的原因是当某个线程操作车票的过程中,操作尚未完成,其他线程进入,也操作了 该车票。如何解决?当一个线程a在操作ticket的时候,其他线程不能参与进来,直到线程a操作完成, 其他线程才可以操作。可以采用同步解决该问题。

 

操作共享数据的代码,即为需要被同步的代码,不能多包含也不能少包含。

共享数据:多个线程共同操作的变量

同步监视器:俗称,锁。任何一个类的对象,都可以充当锁,但是要去必须多个线程公用一把锁。

 

同步的特点:前提:多个线程。

        解决问题的时候要注意:多个线程使用的是同一个锁对象。

        同步的好处:同步的出现解决了多线程的安全问题。

        同步弊端:当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会 降低程序的运行效率。

synchronized: 同步,需要被同步的代码。

        同步方法,仍然需要同步监视器,只是不需要显示声明

        非静态的同步方法,同步监视器是this

        静态的同步方法,同步监视器是 当前类本身。

        死锁 : 不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源, 就形成了死锁。出现死锁后,不会出现异常,不会出现提升,只是所有的线程都处于阻塞状态,无法继 续。解决办法:专门的算法,原则。尽量减少同步资源的定义,尽量避免嵌套同步。

 

 

 

如何避免死锁呢?加锁顺序(线程按照一定的顺序加锁)。加锁时限(线程尝试获取锁的时候加上一定 的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)。死锁检测。

Lock(锁): 从JDK5.0开始, java提供了更强大的线程同步机制。通过显示定义同步锁对象来实现同步。同 步锁使用Lock对象充当。该接口是控制多个线程对共享资源进行访问的公交。锁提供了对共享资源的独 占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。

ReentrantLock类实现了Lock接口,他拥有与synchronized相同的并发性盒内存语义,再实现线程安全 的控制中,比较常用的RenntrantLock可以显示的加锁和释放锁。

 

synchronized与lock的异同:二者都可以解决线程安全问题。 synchronized机制再执行完相应的同 步代码以后,自动的释放同步监视器。 Lock需要手动的启动同步(lock()),同时结束同步也需要手动的 实现(unlock())

练习:两个用户分布向一个账户存3000元,每次存1 000,存3次。每次存款后打印账户余额。

 


2、线程之间的通信

 

wait方法,一旦执行,线程进入阻塞状态,并释放对象的锁。

notify方法,一旦执行,会唤醒等待的线程,如果有多个线程,唤醒优先级高的

notifyAll方法,会 唤醒所有等待的线程。 这三个方便必须再同步方法或同步代码块中使用。

sleep和wait方法的异同?相同点:一旦执行方法,都可以使得当前的线程进入阻塞状态。 不同点:两个方法声明的位置不同, Thread中是sleep方法。 Object类中是wait方法。 调用的范围不同: sleep方法可以再任何需要的场景下调用。 wait必须在同步代码块中运行。如果两个方 法都用在同步代码块或同步方法中, sleep不会释放对象锁。 wait方法会释放锁。

生产者与消费者

 


3、其他创建线程方式

<1 > 实现Callable接口

<2>线程池:经常创建和销毁,使用量特别大的资源,比如并发情况下的线程,对性能影响很大。如何 解决?提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁的创建 销毁,实现重复利用。使用线程池的 好处:提高响应速度,减少了创建新线程的时间,降低资源消耗, 重复利用线程池中的线程,不需要每次都创建。便于线程管理。有一些属性: corePoolSize:核心池的大 小, maxnumPoolSize:最大线程数, keeAliveTime:线程没有任务时最多保持多长时间会终止。

 

练习: 1、模拟医院叫号。一天有50个普通号, 1 0个专家号。专家号的优先级高,专家号看诊时间是普 通号的2倍,当普通号叫到第1 0号的时候,把所有的所有的专家号叫完再叫普通号。

2、某账户中有20万元,先有急事需要全部取出。 ATM机上,一次最多只能取1万,可以分多次取,也可 以在多台ATM上同时登录来取。 试用程序模拟在3台ATM上的取款记录 如:在1号ATM上取款1万,卡里 余额1 9万 在2号ATM上取款1万,卡里余额1 8万 。

3,编写打印数字的线程NumberPrinter继承Thread类,声明私有属性private Printer p;在构造方法中进 行赋值,实现父类的run方法,调用Printer类中的输出数字的方法。

 

4,编写打印字母的线程LetterPrinter继承Thread类,声明私有属性private Printer p;在构造方法中进行 赋值,实现父类的run方法,调用Printer类中的输出字母的方法。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值