Thread对象代表了一个线程,但是并不是说创建了一个线程对象后就有了一个线程!
线程的堆空间共享,栈空间独立。
只有处于运行状态的线程才能执行,代码正在执行说明该代码所在的线程正处在运行状态。例如:t1.start()执行后使t1线程进入可运行状态,因为当时main方法正在运行状态。
创建线程两种方式:1.继承Thread类,2.实现Runnable接口,例如MyRunnable类实现了Runnable接口,则创建一个线程对象的步骤应该为:Runnable myr = new MyRunnable();Thread a = new Thread(myr); a.start();
多线程共同访问了同一个对象(临界资源),如果破坏了不可分割的操作(原子操作),就会造成数据不一致的情况。
在Java中,任何对象都有一个互斥锁标记,用来分配给线程。
synchronized的两种用法:
1. synchronized(o){****},{****}为对对象o加锁的同步代码块,只有拿到o的锁标记的线程,才能进入对对象o加锁的同步代码块,退出同步代码块,会自动释放o的锁标记。
synchronized是对对象加锁!!
2. public synchronized void m(){} 同步方法,对m()方法加锁,哪个线程能拿到对象的锁,哪个线程就能调用对象的同步方法。
在Java中,任何对象都有一个锁池,用来存放等待该对象锁标记的线程。
例如,线程要对a对象访问,又拿不到a对象的锁标记,于是就进入a对象的锁池。
一个线程,可以同时拥有多个对象的锁标记(即可以同时锁住多个对象供自己访问,也就是说synchronized代码块可以嵌套。),线程阻塞在对象锁池中时,不会释放其所拥有的其他对象的锁标记。
Vector 慢,是因为其所有的方法都实现了同步标记,即,用synchronized加锁了。当然了,速度慢,也有因为Vector是数组实现的原因。
ArrayList 较快。ArrayList中的所有方法都不是同步方法,所以可能出现数据不同步的现象。
HashMap和Hashtable的线程是否安全也是由此决定的。
在Java中,任何对象都有一个等待队列,用来存放线程。o对象的等待队列是线程主动调用o.wait()方法而进入的,但是一旦进入则必须有其它的线程调用o.notify()或者o.notifyAll()方法才能从o的等待队列中释放一个或者所有的线程;但是如果调用的是o.notify()方法,则只会从等待队列中释放一个线程,同时调用notify方法或者notifyAll方法的线程继续执行o的同步代码块中的代码,继续持有o 的锁标记。
如何调用wait()方法?:t1对o调用wait方法,必须放在对o加锁的同步代码块中!
t1对o调用wait()方法的结果: 1.t1会释放其所拥有的所有锁标记;2.t1会进入o的等待队列。
如何调用notify()方法:
t2对o调用notify/notifyAll方法,也必须放在对o加锁的同步代码块中!
结果是:会从o的等待队列中释放一个(对于notify而言)/全部(对于notifyAll而言)线程, 对t2毫无影响。