参考资料网站:http://ifeve.com/java-concurrency-thread-directory/
1、Java实现线程的两种方式:
1、继承Thread 通过重写run()方法 启动方法:ThreadTest test = new ThreadTest(); test.start();
2、实现Runable通过实现run()方法 启动方法Thread thread = new Thread(new ThreadTest2(),"new Thread Name"); thread.start();
个人觉得优先使用实现Runable,因为线程池可以有效的管理实现了Runnable接口的线程,如果线程池满了,
新的线程就会排队等候执行,直到线程池空闲出来为止。而如果线程是通过实现Thread子类实现的,这将会复杂一些。
注意点:启动线程的方式是start(),不是run()方法,run()方法虽然也能调用并实现相同的功能,但是,事实上,run()方法并非是由刚创建的新线程
所执行的,而是被创建新线程的当前线程所执行了。也就是被执行上面两行代码的线程所执行的。想要让创建的新线程执行run()方法,必须调用新线程
的start方法。
2、线程的内存模型
静态成员变量跟随着类定义一起也存放在堆上。
存放在堆上的对象可以被所有持有对这个对象引用的线程访问。当一个线程可以访问一个对象时,它也可以访问这个对象的成员变量。
如果两个线程同时调用同一个对象上的同一个方法,它们将会都访问这个对象的成员变量,但是每一个线程都拥有这个本地变量的私有拷贝。
3、Java同步块synchronzied
public class MyClass {
public synchronized void log1(String msg1, String msg2){
log.writeln(msg1);
log.writeln(msg2);
}
public void log2(String msg1, String msg2){
synchronized(this){
log.writeln(msg1);
log.writeln(msg2);
}
}
}
public class MyClass {
public static synchronized void log1(String msg1, String msg2){
log.writeln(msg1);
log.writeln(msg2);
}
public static void log2(String msg1, String msg2){
synchronized(MyClass.class){
log.writeln(msg1);
log.writeln(msg2);
}
}
}
如果两个线程引用了两个不同的Counter实例,那么他们可以同时调用add()方法。这些方法调用了不同的对象,
public class Example {
public static void main(String[] args){
Counter counterA = new Counter();
Counter counterB = new Counter();
Thread threadA = new CounterThread(counterA);
Thread threadB = new CounterThread(counterB);
threadA.start();
threadB.start();
}
}
4、线程通信
public class MonitorObject {
}
public class MyWaitNotify {
MonitorObject monitorObject = new MonitorObject();
public void doWait() {
synchronized (monitorObject) {
try {
monitorObject.wait();
} catch (Exception e) {
// TODO: handle exception
}
}
}
public void doNotify() {
synchronized (monitorObject) {
monitorObject.notify();
}
}
}
如你所见,不管是等待线程还是唤醒线程都在同步块里调用wait()和notify()。这是强制性的!一个线程如果没有持有对象锁,将不能调用wait(),
为了避免丢失信号,必须把它们保存在信号类里。在MyWaitNotify的例子中,通知信号应被存储在MyWaitNotify实例的一个成员变量里。以下是MyWaitNotify的修改版本:调用wait()时加个判断条件,如果调用过notify()则不在调用
public class MyWaitNotify2 {
MonitorObject myMonitorObject = new MonitorObject();
boolean wasSignalled = false;
public void doWait() {
synchronized (myMonitorObject) {
if (!wasSignalled) {
try {
myMonitorObject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// clear signal and continue running.
wasSignalled = false;
}
}
public void doNotify() {
synchronized (myMonitorObject) {
wasSignalled = true;
myMonitorObject.notify();
}
}
}
5、死锁
数据库的死锁
更加复杂的死锁场景发生在数据库事务中。一个数据库事务可能由多条SQL更新请求组成。当在一个事务中更新一条记录,这条记录就会被锁住避免其他事务的更新请求,直到第一个事务结束。同一个事务中每一个更新请求都可能会锁住一些记录。当多个事务同时需要对一些相同的记录做更新操作时,就很有可能发生死锁。
因为锁发生在不同的请求中,并且对于一个事务来说不可能提前知道所有它需要的锁,因此很难检测和避免数据库事务中的死锁。
如何避免死锁:1、加锁顺序,2、加锁时限,3、死锁检测;