线程随笔

一、一个线程的创建肯定是由另一个线程完成的。

二、被创建线程的父线程是创建它的线程。

由源代码。详情看init方法。

三、main线程所在的ThreadGroup称为main。

四、构造一个线程的时候如果没有显式地指定ThreadGroup,那么它将和父线程同属一个ThreadGroup。

在默认设置中,子线程和父线程拥有同样的优先级。

五、Thread和Runnable之间的关系:Thread负责线程本身相关的职责和控制,而Runnable则负责逻辑执行单元的部分(run方法)。

六、Thread与StackSize的关系

       stacksize越大则代表着正在线程内方法调用递归的深度就越深,stacksize越小则代表着创建的线程数数量越多。该参数一般情况下不会主动设置,采用默认的值就可以了,默认值是0。

七、线程的创建数量是随着虚拟机栈内存的增多而减少的,也就是一种反比关系。

一个进程内存大小(有最大内存限制)=堆内存+线程数量*栈内存

      栈内存与线程数量也是反比关系。

地址空间:在操作系统中,一个进程的最大内存。

ReservedOsMemory:系统保留内存,一般在136MB左右。

ThreadStackSize:虚拟机栈内存(栈内存)

线程数量=(最大地址空间-JVM堆内存-ReservedOsMemory)/ThreadStackSize(XSS)。

 

八、守护线程

       设置守护线程:线程.setDaemon(true)     为false时代表正常线程。

       若父线程为守护线程,则子线程也为守护线程。反之亦然。

        isDaemon方法判断该线程是否是守护线程。

九、yield方法

yield方法:提醒调度器,愿意放弃当前的CPU资源,如果CPU的资源不紧张,则会忽略这种提醒。调用yield方法会使当前线程从RUNNING状态切换到RUNNABLE状态,一般这个方法不太常用。

十、线程的优先级不能小于1,也不能大于10,如果指定线程优先级大于线程所在group的优先级,那么指定的优先级将会失效,取而代之的是group的最大优先级。线程默认的优先级和它的父类保持一致,一般情况下是5。

十一、不管是Thread的run方法,还是Runnable接口,都是void返回类型,如果想通过某个线程的运行得到结果,就需要自己定义一个返回的接口。

十二、如何关闭一个线程

1:正常关闭

       1、线程结束生命周期正常结束。

       2、捕获中断信号关闭线程

             通过检查线程interrupt的标志来决定是否退出。如果在线程中执行某个可中断方法,则可以通过捕获中断信号来决定是           否退出。

       3、使用volatile开关控制

        因为线程的interrupt标志很有可能被擦除,或者逻辑单元中不会调用任何可中断方法,所有使用volatile修饰的开关flag关闭线程是一种常用的做法。

   2:异常退出

         在线程的执行单元(run)中,是不允许抛出checked异常的。可以将checked异常封装成unchecked异常(RuntimeException)抛出进而结束线程的生命周期。

  3:进程假死

十三、每个对象都与一个monitor相关联,一个monitor的lock的锁只能被一个线程在同一时间获得,在一个线程尝试获得与对象关联monitor的所有权时会发生如下的几件事情。

1、如果monitor的计数器为0,则意味着改monitor的lock还没有被获得,某个线程获得之后将立即对该计数器加一,从此该线程就是这个monitor的所有者了。

2、如果一个已经拥有该monitor所有权的线程重入,则会导致monitor计数器再次累加。

3、如果monitor已经被其他线程所拥有,则其他线程尝试获取该monitor的所有权时,会被陷入阻塞状态直到monitor计数器变为0,才能尝试获取对monitor的所有权。

monitorexit:

释放对monitor的所有权,想要释放对某个对象关联的monitor的所有权的前提是,你曾经获得了所有权。释放monitor所有权,就是将monitor的计数器减一,如果计数器的结果为0,那就意味着该线程不再拥有对该monitor的所有权,通俗讲就是解锁。与此同时被该monitor block的线程将再次尝试获得对该monitor的所有权。

十四、使用synchronized 注意事项:

1、与monitor关联的对象不能为空。

2、synchronized 作用域太大

        

     上面的代码对整个线程的执行逻辑单元都进行了synchronized同步,从而丧失了并发的能力,synchronized关键字应该尽可能地只作用于共享资源(数据)的读写作用域。

3、不同的monitor企图锁相同的方法

 

     上面的代码构造了五个线程,同时也构造了五个Runnable实例,Runnable作为线程逻辑执行单元传递给Thread,然后你将发现。synchronized根本互斥不了与之对应的作用域,线程之间进行monitor lock的争抢只能发生在于monitor关联的同一个引用上,上面的代码每个线程争抢的monitor关联引用都是彼此独立的(每个线程new一个),因此不可能起到互斥的作用。

(解决办法:声明为static)

4、多个锁的交叉导致死锁

十五、 this monitor    class monitor 

1、使用synchronized关键字同步类的不同实例方法,争抢的是同一个monitor的lock,而与之关联的引用则是this monitor的实例引用。

2、用synchronized同步某个类的不同静态方法争抢的也是同一个monitor的lock,与该monitor关联的引用是ClassMonitord.class实例。

十六、线程死锁原因

1、交叉锁可导致程序出现死锁。

2、内存不足

3、一问一答式的数据交换

4、数据库锁

5、文件锁

6、死循环引起的死锁(一般称为系统假死)

十七、被唤醒并且被执行的线程是从上次阻塞的位置从下开始运行,也就是从wait()方法后开始执行。所以判断是否进入某一线程的条件 是用while判断,而不是用If判断。

十八、默认情况下,新的线程都会被加入到main线程所在的group中,main线程的group名字同线程名。如同线程存在父子关系一样,ThreadGroup同样也存在父子关系。无论如何,线程都会被加入某个Thread Group之中。

十九、所有线程的优先级都不能大于group的优先级。group的最大优先级不能超过父group的最大优先级。

二十、修改group的优先级:已经加入该group的线程的优先级可以大于group最大优先级。但是,后面加入该group的线程的优先级再不会大于新设置的优先级。

二十一、interrupt一个thread group会导致该group中所有的active线程都被interrupt,也就是说该group中每个线程的interrupt标志都被设置了。

二十二、线程可以设置为守护线程,ThreadGroup也可以设置为守护ThreadGroup,但是若将一个Threadgroup设置为daemon,也并不会影响线程的daemon属性,如果一个ThreadGroup的daemon被设置为true,那么在group中没有active线程的时候该group将自动destroy。

二十三、钩子线程(Hook线程)

      JVM进程的退出是由于JVM进程中没有活跃的非守护线程,或者收到了系统中断信号,向JVM程序注入一个Hook线程,在JVM进程退出的时候,Hook线程会启动执行,通过Runtime可以为JVM注入多个Hook线程。

package com.lijiangde.fours;

import java.util.concurrent.TimeUnit;

public class ThreadHook {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		//为应用程序注入钩子线程
		Runtime.getRuntime().addShutdownHook(new Thread(){
			public void run()
			{
				try
				{
					System.out.println("The hook thread 1 is running");
					TimeUnit.SECONDS.sleep(1);
				}catch(InterruptedException e)
				{
					e.printStackTrace();
				}
				System.out.println("The hook thread 1 will exit");
			}
		});
		
		//钩子线程可注册多个
		Runtime.getRuntime().addShutdownHook(new Thread(){
		
			public void run()
			{
				try
				{
					System.out.println("The hook thread 2 is running.");
					TimeUnit.SECONDS.sleep(1);
				}catch(InterruptedException e)
				{
					e.printStackTrace();
				}
				System.out.println("The hook thread 2 will exit.");
			}
		});
		System.out.println("The program will is stopping.");

	}

}

二十四、被volatile修饰的实例变量或类变量具备如下两层语义:

1、保证了不同线程之间对共享变量操作时的可见性,也就是说当一个线程修改volatile修饰的变量,另外一个线程会立即看到最新的值。

2、禁止对指令进行重排序操作。

二十五、单例模式   ——Holder方式

public class Singleton {
	
	private byte[] data=new byte[1024];
	private Singleton()
	{
		
	}
	//在静态内部类中持有Singleton的实例,并且可被直接初始化
	private static class Holder
	{
		private static Singleton singleton=new Singleton();
	}
	
	//调用getInstance方法,事实上是获得Holder的instance静态属性
	
	public static Singleton getInstance()
	{
		return Holder.singleton;
	}	

}

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值