Java多线程学习笔记

线程创建两种方式:


1.  继承Thread  

public class MyThread extends Thread {

	@Override
	public void run() {

	}

}
	MyThread t = new MyThread();
	t.start();

2.实现Runnable接口

public class MyRunnable implements Runnable {

	@Override
	public void run() {
	}

}
		Thread t = new Thread(new MyRunnable());
		t.start();

线程的关闭:


1.stop,suspend已经被废弃

2.通常是设置一个变量,让线程自动运行完毕

3.遇到线程阻塞,例如Thread.sleep()、Thread.join、Object.wait()、ServerSocket.accept()和DatagramSocket.receive()时,使用interrupt中断线程


第三种情况,需要先设置变量,然后使用interrupt中断。interrupt并不会关闭线程,只是跳出阻塞,就是让代码进入 InterruptedException

	        try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

Socket阻塞,使用interrupt无效,需要给Socket保存一个实例,然后使用它的close方法,最后会抛出异常

                Socket sock;
		try {
			sock = socket.accept();
		} catch (IOException e) {
			e.printStackTrace();
		}


线程优先级:


优先级高的线程会获得较多的运行机会。
 
Java线程的优先级用整数表示,取值范围是1~10(但是每个操作系统不一定都支持,所以最后用下面3个常量),Thread类有以下三个静态常量:
static int MAX_PRIORITY
          线程可以具有的最高优先级,取值为10。
static int MIN_PRIORITY
          线程可以具有的最低优先级,取值为1。
static int NORM_PRIORITY
          分配给线程的默认优先级,取值为5。
 
Thread类的setPriority()和getPriority()方法分别用来设置和获取线程的优先级。

主线程的默认优先级为Thread.NORM_PRIORITY


线程状态转换:


1、新建状态(New):新创建了一个线程对象。
2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。



.join   理解的意思是。    我本线程,加入另外一个线程,让他阻塞。我运行完了,他才运行。   就是加入你,抢你的运行权!!!





1、synchronized关键字的作用域有二种: 
1)是某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一


个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象


中任何一个synchronized方法)。这时,不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样


可以同时访问相同类的另一个对象实例中的synchronized方法; 
2)是某个类的范围,synchronized static aStaticMethod{}防止多个线程同时访问这个类中的synchronized static 


方法。它可以对类的所有对象实例起作用。 


2、除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资


源实行互斥访问。用法是: synchronized(this){/*区块*/},它的作用域是当前对象; 


3、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是


synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法; 


Java对多线程的支持与同步机制深受大家的喜爱,似乎看起来使用了synchronized关键字就可以轻松地解决多线程共享


数据同步问题。到底如何?――还得对synchronized关键字的作用进行深入了解才可定论。


总的说来,synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句


块。如果再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class 


literals(类名称字面常量)身上。


在进一步阐述之前,我们需要明确几点:


A.无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁――而且同


步方法很可能还会被其他线程的对象访问。


B.每个对象只有一个锁(lock)与之相关联。


C.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。


接着来讨论synchronized用到不同地方对代码产生的影响:


 


假设P1、P2是同一个类的不同对象,这个类中定义了以下几种情况的同步块或同步方法,P1、P2就都可以调用它们。


 


1.  把synchronized当作函数修饰符时,示例代码如下:


Public synchronized void methodAAA()


{


//….


}


这也就是同步方法,那这时synchronized锁定的是哪个对象呢?它锁定的是调用这个同步方法对象。也就是说,当一个


对象P1在不同的线程中执行这个同步方法时,它们之间会形成互斥,达到同步的效果。但是这个对象所属的Class所产生


的另一对象P2却可以任意调用这个被加了synchronized关键字的方法。


上边的示例代码等同于如下代码:


public void methodAAA()


{


synchronized (this)      //  (1)


{


       //…..


}


}


 (1)处的this指的是什么呢?它指的就是调用这个方法的对象,如P1。可见同步方法实质是将synchronized作用于


object reference。――那个拿到了P1对象锁的线程,才可以调用P1的同步方法,而对P2而言,P1这个锁与它毫不相干


,程序也可能在这种情形下摆脱同步机制的控制,造成数据混乱:(


2.同步块,示例代码如下:


            public void method3(SomeObject so)


              {


                     synchronized(so)


{


       //…..


}


}


这时,锁就是so这个对象,谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时,就可以这


样写程序,但当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的instance变量(它得是一个对


象)来充当锁:


class Foo implements Runnable


{


       private byte[] lock = new byte[0];  // 特殊的instance变量


    Public void methodA()


{


       synchronized(lock) { //… }


}


//…..


}


注:零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码:生成零长度的byte[]对象只需3条操


作码,而Object lock = new Object()则需要7行操作码。


3.将synchronized作用于static 函数,示例代码如下:


      Class Foo


{


public synchronized static void methodAAA()   // 同步的static 函数


{


//….


}


public void methodBBB()


{


       synchronized(Foo.class)   //  class literal(类名称字面常量)


}


       }


   代码中的methodBBB()方法是把class literal作为锁的情况,它和同步的static函数产生的效果是一样的,取得的


锁很特别,是当前调用这个方法的对象所属的类(Class,而不再是由这个Class产生的某个具体对象了)。


记得在《Effective Java》一书中看到过将 Foo.class和 P1.getClass()用于作同步锁还不一样,不能用


P1.getClass()来达到锁这个Class的目的。P1指的是由Foo类产生的对象。


可以推断:如果一个类中定义了一个synchronized的static函数A,也定义了一个synchronized 的instance函数B,那


么这个类的同一对象Obj在多线程中分别访问A和B两个方法时,不会构成同步,因为它们的锁都不一样。A方法的锁是Obj


这个对象,而B的锁是Obj所属的那个Class。






1、线程同步的目的是为了保护多个线程反问一个资源时对资源的破坏。


2、线程同步方法是通过锁来实现,每个对象都有切仅有一个锁,这个锁与一个特定的对象关联,线程一旦获取了对象锁


,其他访问该对象的线程就无法再访问该对象的其他非同步方法。


3、对于静态同步方法,锁是针对这个类的,锁对象是该类的Class对象。静态和非静态方法的锁互不干预。一个线程获


得锁,当在一个同步方法中访问另外对象上的同步方法时,会获取这两个对象锁。


4、对于同步,要时刻清醒在哪个对象上同步,这是关键。


5、编写线程安全的类,需要时刻注意对多个线程竞争访问资源的逻辑和安全做出正确的判断,对“原子”操作做出分析


,并保证原子操作期间别的线程无法访问竞争资源。


6、当多个线程等待一个对象锁时,没有获取到锁的线程将发生阻塞。


7、死锁是线程间相互等待锁锁造成的,在实际中发生的概率非常的小。真让你写个死锁程序,不一定好使,呵呵。但是


,一旦程序发生死锁,程序将死掉。

void notifyAll()

解除所有那些在该对象上调用wait方法的线程的阻塞状态。该方法只能在同步方法同步块内部调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。

void notify()

随机选择一个在该对象上调用wait方法的线程,解除其阻塞状态。该方法只能在同步方法同步块内部调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。

void wait()

导致线程进入等待状态,直到它被其他线程通过notify()或者notifyAll唤醒。该方法只能在同步方法中调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。


  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值