1.在java中,每个线程对象都是一个继承了java.util.Thread类的对象或者implements了java.util.Runnabel接口类的对象,线程的启动是通过调用线程对象的start()方法进行的,线程运行是从线程对象的run方法开始,当线程对象的run()方法结束后,线程即运行结束。
2.按照线程体在计算机系统内存中的状态不同,可以将线程分为:
1.创建、 2.就绪、 3.运行、 4.睡眠、 5.挂起 6.死亡
这些线程状态类型下线程的特征为:
1.创建状态:当利用new关键字创建线程对象实例后,它仅仅作为一个对象实例存在,JVM没有为其分配CPU时间片等线程运行资源;
2.就绪状态:在处于创建状态的线程中调用start方法将线程的状态转换为就绪状态。这时,线程已经得到除CPU时间之外的其它系统资源,只等JVM的线程调度器按照线程的优先级对该线程进行调度,从而使该线程拥有能够获得CPU时间片的机会。
3.睡眠状态:在线程运行过程中可以调用sleep方法并在方法参数中指定线程的睡眠时间将线程状态转换为睡眠状态。这时,该线程在不释放占用资源的情况下停止运行指定的睡眠时间。时间到达后,线程重新由JVM线程调度器进行调度和管理。
4.挂起状态:可以通过调用suspend方法将线程的状态转换为挂起状态。这时,线程将释放占用的所有资源,由JVM调度转入临时存储空间,直至应用程序调用resume方法恢复线程运行。
5.死亡状态:当线程体运行结束或者调用线程对象的stop方法后线程将终止运行,由JVM收回线程占用的资源。
同步:是一种防止对共享资源访问导致的数据不一致的一种模式。
在Java中,由于对多线程的支持,对同步的控制主要通过以下几个方法,synchronized,和wait(),notify()和notifyAll(),:
A关键字synchronized
每个java对象都有一把锁, 当有多个线程同时访问共享资源的时候, 需要Synchronize 来控制安全性, synchronized分 synchronized方法 和synchronized块,使用synchronized块时,一定要显式的获得该对象的锁(如synchronized(object))而方法则不需要。
java的内存模型是对每一个进程有一个主内存, 每个线程有自己的内存, 他们从主内存中取数据, 然后计算,再存入主内存中。
并发问题如下:如果多个线程同事操作同一数据, A线程从主内存中取的I的值为1, 然后进行加1操作,这时B线程也取I的值,进行加2操作,然后A存入2到主内存中, B也存入,这样就覆盖了A的值(同数据库中的并发问题一样)。
解决办法是用synchronize, 如用synchronized(I)。被synchronize 修饰的方法(块)把以下三步操作当成一个原子操作:取数据,操作数据,存数据。 我们知道原子操作是不可以被打断的, 所以其保证了数据一致性, 这样同一时间只有一个线程再执行,对性能有一定的影响。这也是synchronize的第二个作用:保证统一时间只有一个线程再运行。当实现SOCKET连接的时候经常用到.
JAVA中规定对非FLOAT, LONG的原始类型的取和存操作为原子操作。其实就是对一个字(32位)的取,存位原始操作, 因为FLOAT, LONG为两个字节的长度,所以其取, 存为非原子操作。 如果想把他们也变为原子操作, 可以用VOLATILE关键字来修饰
B.wait()/notify()/notifyAll()
在Java中,每个对象都有个对象锁标志(Object lock flag)与之想关联,当一个线程A调用对象的一段synchronized代码时, 它首先要获取与这个对象关联的对象锁标志,然后执行相应的代码,执行结束后,把这个对象锁标志返回给对象;因此,在线程A执行 synchronized代码期间,如果另一个线程B也要执行同一对象的一段synchronized代码时(不一定与线程A执行的相同),它将 要等到线程A执行完后,才能继续....
如何利用wait() notify() notifyAll()?
在synchronized代码被执行期间,线程可以调用对象的wait()方法,释放对象锁标志,进入等待状态,并且可以调用notify()或者 notifyAll()方法通知正在等待的其他线程。notify()通知等待队列中的第一个线程,notifyAll()通知的是等待队列中的所有线程.
参考文献: <!--StartFragment -->