书的这一章主要讨论的是多线程的使用以及关于多线程中访问共享数据中遇到的问题。首先总结一下多线程的使用方法。方法有2种,第一种是直接继承 Thread类,然后在public void run()写入需要用在线程的代码。作完以后只需要调用start()方法,就会开始新开一个线程并执行run()中的代码了。另外一种方法是使用 runnable接口,同样需要使用线程的代码写入run()方法中,不过线程运行上有所不同,必须先声明一个Thread对象,再用这个Thread对象调用start()方法。
第二种方法的示例代码:
class test implements Runnable
{
private Thread t;
public test()
{
t = new Thread(this);
t.start();
}
public void run() {}
}
虽然看起来第二种方法比较麻烦,但是如果同时要从一个类继承而且也必须使用线程的话,那么只能使用runnable接口了。
线程虽然提供了很大的灵活性,但是同时也带来了问题。如果多个线程同时访问一个共享资源,有的线程进行读取有的进行写入。这样的话显然会发生问题。这时候我们只能用java提供的同步锁(synchronized关键字)来解决。加上了同样同步锁的代码块如果被多个线程同时访问的时候,只有获得锁的线程对代码进行执行,而其他线程则必须等待,直到获得锁的线程执行完锁住的代码释放了所以后,其余的线程才能按照一定的顺序获得锁逐个执行被锁住的代码。
然而我们在使用synchronized关键字解决了共享数据访问问题的同时,又出现了新的问题:那就是synchronized使用不当造成死锁。比较常见的情况是,几个拥有同样同步锁的线程陷入一个循环等待。也就是说获得同步锁的当前线程A必须等待线程B运行完成才能继续,而线程B必须等待线程C执行完。而线程C与当前线程A具有相同的同步锁,那么线程C必须等待线程A运行完成才能运行。从上面的叙述可能很明显的看出这些线程已经彻底锁死,不可能运行下去了。
之后讨论的是对线程进行控制的几种方法:
(1) 调用sleep(毫秒数),使线程进入“睡眠”状态。在规定的时间内,这个线程是不会运行的。
(2) 用suspend()暂停了线程的执行。除非线程收到resume()消息,否则不会返回“可运行”状态。使用suspend()方法进行线程暂停状态,不会释放同步锁,如果resume()消息正好处于具有同样同步锁的另一个代码块中,那么这里就会产生死锁。所以这种方法相当危险,在java1.2中已经被设定为过时的,并且极力反对使用。
(3) 用wait()暂停了线程的执行。除非线程收到nofify()或者notifyAll()消息,否则不会变成“可运行”。使用wait()会自动释放锁,所以应优先考虑这种方法
(4)stop()该方法会停止一个线程并释放锁,但是java1.2中也对这种方法提出了反对。
书中给出代替stop()停止一个线程的方法是:
public void terminate() { stop = true; }
public void run()
{
while (!stop)
{
status.setText(b.getClass().getName() + " Peeker " + (++session) + "; value = " + b.read());
try
{
sleep(100);
}
catch (InterruptedException e){}
}
}
用这样一个自己编写的方法代替stop()方法。
最后是关于线程优先级以及线程组的问题。对于线程优先级的测试程序,1优先级与10优先级的计数器运行的结果几乎没什么差距,我想大概在线程较多且较复杂的时候才会体现出来吧。而对于线程组整体管理线程的方法因为没有任何实际经验,所以对于这种管理并没有什么感想。
think in java第十四章关于多线程的读书笔记
最新推荐文章于 2024-09-05 11:00:53 发布