JavaSE学习笔记(17.Java线程与并发)

1. 创建线程

Java线程的使用,都是基于Thread类完成的;通过Thread实例的start()方法,来回调run()方法,run方法为目标子线程的执行体!

1.1 通过继承Thread类来构造Thread实例:

public class ThreadCase 
{
	public static void main(String args[])
	{
		ThreadTest thread = new ThreadTest();
		System.out.println("main " + Thread.currentThread().getName());
		thread.start();
	}
}

class ThreadTest extends Thread
{
	@Override
	public void run()
	{
		System.out.println("ThreadTest " + Thread.currentThread().getName());
	}
}

PS:

  • 通过继承Thread类来重写run()方法,构造子线程执行体!
  • 当一个Thread实例调用过start()方法后,不可以再重复调用start()方法,否则会抛出java.lang.IllegalThreadStateException异常,如果需要重启线程,需要重写实例化新的Thread实例!!!

1.2 通过Runnable实例来构造Thread实例:

public class ThreadCase 
{
	public static void main(String args[])
	{
		RunnableTest runnableTest = new RunnableTest();
		System.out.println("main " + Thread.currentThread().getName());
		Thread thread = new Thread(runnableTest);
		thread.start();
	}
}

class RunnableTest implements Runnable
{
	@Override
	public void run()
	{
		System.out.println("ThreadTest " + Thread.currentThread().getName());
	}
}

PS:

  • 实现Runnable接口中的run()方法,并通过该实现类构造Thread实例,将实现类种的run()方法挂接到Thread实例中去,再通过start()方法回调run()方法!如果用无参构造器构造的Thread实例,start()回调的run()方法为一个空方法!
  • Runnable实现类中的run方法,不可以通过throws显示抛出任何异常(无论是RuntimeException还是CheckException),因为Runnable接口中的run方法未显示抛出任何异常类型,子类中重写父类中的方法显示抛出异常类型不可以大于父类方法!

1.3 通过Callable实例来构造Thread实例(Java1.5开始支持):

public class ThreadCase 
{
	public static void main(String args[])
	{
		System.out.println("Main " + Thread.currentThread().getName());
		CallableTest call = new CallableTest();
		FutureTask<String> task = new FutureTask<>(call);
		
		Thread thread = new Thread(task);
		thread.start();
		
		try
		{
			System.out.println("Main " + task.get());
		}
		catch (InterruptedException | ExecutionException e)
		{
			e.printStackTrace();
		}
		
	}
}

class CallableTest implements Callable<String>
{
	@Override
	public String call() throws Exception 
	{
		System.out.println("CallableTest " + Thread.currentThread().getName());
		return "CallableTest " + Thread.currentThread().getName();
	}	
}

PS:

  • Callable实现类中实现call()方法,通过Callable实现类来构造FutureTask实例,FutureTask继承自Runnable接口;FutureTask中的run()方法调用Callable实现中的call()方法,进而构成Thread实例的回调方法!
  • 通过Callable实现的子线程,父线程中可以通过FutureTask实例的get()方法拿到子线程执行体的返回值,同时也可以捕获到子线程中的异常!
  • FutureTask实例的get()方法,会阻塞主线程,直到子线程执行完成!
  • FutureTask实例只会被Thread实例start一次,当被其他Thread实例再次start的时候,FutureTask中的状态已经不是NEW,则线程执行体不会再次执行

代码逻辑如下:

/*FutureTask类中run方法实现*/
public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

1.4 Runnable和Callable在Java1.8开始,都被@FunctionalInterface修饰,是函数式接口,可以使用Lamda表达式构造!

public class ThreadCase 
{
	public static void main(String args[])
	{
		System.out.println("main " + Thread.currentThread().getName());
		
		/*Runnable示例*/
		Thread thread = new Thread(()->
		{
			System.out.println("ThreadTest " + Thread.currentThread().getName());
		});
		thread.start();
		
		/*Callable示例*/
		FutureTask<String> task = new FutureTask<>(()->
		{
			System.out.println("CallableTest " + Thread.currentThread().getName());
			return "CallableTest " + Thread.currentThread().getName();
		}); 
		
		Thread thread1 = new Thread(task);
		thread1.start();
		
		try
		{
			System.out.println("Main " + task.get());
		}
		catch (InterruptedException | ExecutionException e)
		{
			e.printStackTrace();
		}
	}
}

 

2.线程同步:

2.1 同步代码块:

使用synchronized关键字定义同步监视器,任何一个对象都可以被定义为同步监视器,但null对象会报错;同步监视器其实就是一个对象,当前线程执行同步代码块前,先去获取这个同步监视器对象,如果这个对象被其他线程所持有者,则当前线程阻塞并等待其他线程释放该对象,如果当前线程获取到该对象,则开始执行同步代码块中的逻辑代码!

public class ThreadCase 
{
	
	public static void main(String args[])
	{
		String lock = "Lock1";
		RunnableTest runnableTest = new RunnableTest(lock);
		System.out.println("main " + Thread.currentThread().getName());
		Thread thread = new Thread(runnableTest);
		thread.start();
		
		String lock1 = "Lock2";
		//共用lock对象最为同步监视器,thread1线程要等thread线程跑完才能执行
		//RunnableTest1 runnableTest1 = new RunnableTest1(lock);	
		//由于lock和lock1不是同一个同步监视器,thread1线程可以和thread线程串行运行
		RunnableTest1 runnableTest1 = new RunnableTest1(lock1);		
		Thread thread1 = new Thread(runnableTest1);
		thread1.start();
	}
}

class RunnableTest implements Runnable
{
	private String lock;
	
	public RunnableTest(String lock)
	{
		this.lock = lock;
	}
	
	@Override
	public void run()
	{
		synchronized (lock)
		{
			try
			{
				for (int i = 0; i < 10; i++)
				{
					System.out.println("ThreadTest" + i + " " + Thread.currentThread().getName());
					Thread.sleep(1);
				}				
			}
			catch (InterruptedException e)
			{
				
			}
		}		
	}
}

class RunnableTest1 implements Runnable
{
	private String lock;
	
	public RunnableTest1(String lock)
	{
		this.lock = lock;
	}
	
	@Override
	public void run()
	{
		synchronized (lock)
		{
			try
			{
				for (int i = 0; i < 10; i++)
				{
					System.out.println("ThreadTest" + i + " " + Thread.currentThread().getName());
					Thread.sleep(1);
				}
			}
			catch (InterruptedException e)
			{
				
			}
			
		}		
	}
}

2.2 同步方法:

使用synchronized关键字修饰实例方法,默认的同步监视器为该实例方法的实例对象(this);修饰类方法,默认的同步监视器该类方法的类对象(XXX.class),同步块为同步方法的方法体!

public class ThreadCase 
{
	
	public static void main(String args[])
	{
		System.out.println("main " + Thread.currentThread().getName());
		
		FunTest test = new FunTest();
		RunnableTest runnableTest = new RunnableTest(test);
		FunTest test1 = new FunTest();
		RunnableTest runnableTest1 = new RunnableTest(test1);	
		
		Thread thread = new Thread(runnableTest);
		thread.start();
		Thread thread1 = new Thread(runnableTest1);
		thread1.start();
	}
}

class RunnableTest implements Runnable
{
	private FunTest test;
	
	public RunnableTest(FunTest test)
	{
		this.test = test;
	}
	
	@Override
	public void run()
	{
		this.test.fun();	
	}
	
}

class FunTest
{
	/*同步监视器为FunTest的实例this*/
	public synchronized void fun()
	{
		try
		{
			for (int i = 0; i < 10; i++)
			{
				System.out.println("ThreadTest" + i + " " + Thread.currentThread().getName());
				Thread.sleep(1);
			}				
		}
		catch (InterruptedException e)
		{
			
		}
	}
	
	/*同步监视器为FunTest的实例this*/
	public void fun1()
	{
		synchronized (this)
		{
			try
			{
				for (int i = 0; i < 10; i++)
				{
					System.out.println("ThreadTest" + i + " " + Thread.currentThread().getName());
					Thread.sleep(1);
				}				
			}
			catch (InterruptedException e)
			{
				
			}
		}
	}
	
	/*同步监视器为FunTest类*/
	public synchronized static void fun2()
	{
		try
		{
			for (int i = 0; i < 10; i++)
			{
				System.out.println("ThreadTest" + i + " " + Thread.currentThread().getName());
				Thread.sleep(1);
			}				
		}
		catch (InterruptedException e)
		{
			
		}
	}
}

PS:

  • synchronized只能修饰对象(实例对象和.class对象)、类方法和实例方法,其他成员不能修饰;当修饰实例对象的时候,为对象锁;当修饰.class对象时,为类锁!
  • 同步监视器的释放:同步代码块异常或正常执行结束释放监视器,当前线程调用wait()方法释放监视器;sleep()、yeild()、suspend()方法调用,不会释放监视器!

2.3 synchronized的可重入性:

当synchronized获取到同步监视器的使用权后,在当前线程的同步代码块或同步方法中该同步监视器可以重复获取,这就是synchronized的可重入性!

public class ThreadCase 
{
	static public String lock = "lock";
	
	public static void main(String args[]) throws InterruptedException 
	{
		
		synchronized (ThreadCase.lock)
		{
			/*新启动线程,获取不到同步监视器的使用权,直到主线程执行完成*/
			Thread thread = new Thread(new Run());
			thread.start();
			System.out.println("Main 11111!");
				
			/*获取同步监视器后,同步代码块中依然可以重复获取该同步监视器的使用权*/
			synchronized (ThreadCase.lock)
			{
				System.out.println("Main 22222!");
				Thread.sleep(10000);
				System.out.println("Main finish!");
			}
		}
		
	}

}

class Run implements Runnable
{
	@Override
	public void run() 
	{
		synchronized (ThreadCase.lock)
		{
			System.out.println("Run Begin!");
			try 
			{
				Thread.sleep(5000);
				
			} 
			catch (InterruptedException e) 
			{
				e.printStackTrace();
			}
			System.out.println("Run Finish!");
		}
		
	}
}

执行结果:

2.4 lock锁:

2.4.1 lock接口:

lock锁都实现于lock接口,lock接口中提供了四个获取锁的方法,一个释放锁的方法,一个锁间通信的方法

public interface Lock {

    /*获取lock锁,如果lock正在被占用,线程阻塞等待*/
    void lock();

    /*当线程正在阻塞等待获取lock锁的时候,可以被线程实例的interrupt()方法打断*/
    void lockInterruptibly() throws InterruptedException;

    /*尝试获取lock锁,如果获取成功返回true,获取失败返回false*/
    boolean tryLock();

    /*尝试获取lock锁,如果未获取到阻塞等待time时长,成功返回true,失败返回false*/
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

    /*释放lock锁*/
    void unlock();
    
    /*获取当前lock的Condition实例*/
    Condition newCondition();
}

Ps:获取lock锁后,锁是不会自动释放的,所以在异常流程和结束流程中一定要明确的手动调用unlock()释放锁!

2.4.2 常用lock实现类:

ReentrantLock实现类(可重入锁):后面详细介绍,这里不再展开!

ReadWriteLock接口(读写锁接口):由于读写操作是同步锁的主要应用场景,如果使用可重入锁,会导致所有对数据的读写操作都发生线程竞争,实际上只需要并发处理读写、写写两种并发场景,读读场景是不需要互斥的!这样就引入了读写锁的概念!

public interface ReadWriteLock {
    Lock readLock();

    Lock writeLock();
}

ReentrantReadWriteLock实现类(读写锁):

  • 继承ReadWriteLock接口
  • ReentrantReadWriteLock中实际上是两个有消息交互的锁
  • 多线程之间没有占用写锁的时候,读锁与读锁之间并不会造成线程竞争!
  • 读锁不支持Conditon,readLock().newCondition() 会抛出 UnsupportedOperationException
  • 支持锁的降级,在一个线程中先获取了写锁后,在写锁释放前,可以成功获取到读锁!反之不可以!
  • ReentrantReadWriteLock锁,支持重入,重入规则与synchronized重入规则相同!

StampedLock实现类(读写锁):

  • StampedLock锁是对ReentrantReadWriteLock锁升级的读写锁,在读锁的基础上增加了乐观读锁,提高了读锁的效率
  • 获取读锁tryReadLock()、获取写锁tryWriteLock()、获取乐观读锁tryOptimisticRead()、都会返回一个long型的时间戳;读锁和写锁的使用比较简单,直接在解锁的时候传入这个时间戳即可!当使用乐观读锁的时候,需要在获取共享数据后,再通过validate()方法,判断下时间戳是否有效(再获取乐观锁后,是否有写锁被获取);如果有效,正常使用;如果无效,需要再使用重新申请下悲观读锁,再重新获取下数据,示例代码如下!
  • StampedLock锁不支持Condition等待
  • StampedLock锁不支持重入
  • StampedLock锁支持读锁和写锁的相互转换功能
  • ReentrantReadWriteLock和StampedLock锁都适用于读操作远大于写操作的场景!

StampedLock乐观读锁示例代码:

class Point {
  private int x, y;
  final StampedLock sl = new StampedLock();
  // 计算到原点的距离
  int distanceFromOrigin() {
    // 乐观读
    long stamp =
      sl.tryOptimisticRead();
    // 读入局部变量,
    // 读的过程数据可能被修改
    int curX = x, curY = y;
    // 判断执行读操作期间,
    // 是否存在写操作,如果存在,
    // 则 sl.validate 返回 false
    if (!sl.validate(stamp)){
      // 升级为悲观读锁
      stamp = sl.readLock();
      try {
        curX = x;
        curY = y;
      } finally {
        // 释放悲观读锁
        sl.unlockRead(stamp);
      }
    }
    return Math.sqrt(
      curX * curX + curY * curY);
  }
}

Ps:这里先简单阐述下这个几种常用锁的使用方式和场景,实现原理后续再补充!

2.4.3 ReentrantLock可重入锁的使用:

ReentrantLock使用示例:

public class ThreadCase 
{
	static public ReentrantLock lock = new ReentrantLock();
	
	
	public static void main(String args[]) throws InterruptedException 
	{
		ThreadCase.lock.lock();
		
		try
		{
			/*新启动线程,获取不到同步监视器的使用权,直到主线程执行完成*/
			Thread thread = new Thread(new Run());
			System.out.println("Main 11111!");
				
			/*获取同步监视器后,同步代码块中依然继承该同步监视器的使用权*/
			ThreadCase.lock.lock();
			try
			{
				System.out.println("Main 22222!");
				Thread.sleep(10000);
				System.out.println("Main finish!");
			}
			finally
			{
				ThreadCase.lock.unlock();
			}
			
		}
		finally
		{
			ThreadCase.lock.unlock();
		}
		
	}

}

class Run implements Runnable
{
	@Override
	public void run() 
	{
		ThreadCase.lock.lock();
		try
		{
			System.out.println("Run Begin!");
			Thread.sleep(5000);
			
			System.out.println("Run Finish!");
		}
		catch (InterruptedException e) 
		{
			e.printStackTrace();
		}
		finally
		{
			ThreadCase.lock.unlock();
		}
		
	}
}

Ps:ReentrantLock的重入原则与synchronized的重入原则一致,这里不再详细说明!

2.4.4 Condition类的使用:

在Synchronized同步代码中,调用wait()、notify()方法,可以实现”等待-通知“功能;在lock锁中同样提供了相同的能力,通过lock接口中newCondition()方法获取当前lock锁的Condition对象,通过Condition对象的await()、signal()方法来实现“等待-通知”功能!

2.4.5 ReentrantLock与synchronized的关系:

  • ReentrantLock是lock的实现类,synchronized是Java关键字
  • ReentrantLock与synchronized都实现可重入锁的功能
  • ReentrantLock相对更加灵活,支持可以中断阻塞的获取锁方法;可以选择使用公平锁或非公平锁;synchronized只能使用非公平锁,ReentrantLock的公平锁可以解决线程饥饿的问题
  • synchronized锁的使用,只要同步代码块执行完成,锁会自动释放;ReentrantLock锁的使用,需要手动释放,同时要匹配重入次数,如果获取次数和释放次数不匹配,会导致锁获取不到,最好在finally块中完成锁的释放!

 

3. Thread类方法说明:

3.1 currentThread()方法:

public static native Thread currentThread();

Thread类的类方法,获取当前线程的Thread实例!

3.2 sleep(long millis)、sleep(long millis, int nanos)方法:

public static native void sleep(long millis) throws InterruptedException;
public static void sleep(long millis, int nanos) throws InterruptedException

Thread类方法,sleep()方法,使当前线程等待,等待时间为方法入参,单位毫秒+纳秒;sleep()方法会释放处理器资源,使当前线程阻塞,并持有线程所有的同步监视器!

3.3 yield()方法(线程让位):

public static native void yield();

Thread类的类方法,当前线程短暂停止,将处理器让给优先级更高的线程任务(线程优先级设置在本节后面介绍)!

  • yeild操作不会释放同步监视器
  • 在多CPU场景下,yield的功能并不明显;
  • sleep会让线程阻塞,yeild则只是短暂停止
  • sleep让出处理器资源并不区分线程优先级,yeild只会让给比他优先级高的线程

3.4 join()方法(保证当前线程和线程实例的执行顺序):

public final synchronized void join(long millis) throws InterruptedException
public final synchronized void join(long millis, int nanos) throws InterruptedException
public final void join() throws InterruptedException

public final void wait() throws InterruptedException
public final native void wait(long timeout) throws InterruptedException
public final void wait(long timeout, int nanos) throws InterruptedException 

public final native void notify()
public final native void notifyAll()
  • Thread类的实例方法,join()方法阻塞当前线程xxx毫秒+xxx纳秒或者一直阻塞直到线程实例执行完成,恢复当前线程的阻塞,用来保证当前线程和线程实例的执行顺序!
  • join()方法的实现依赖与Object类的wait()、notify()、notifyall()方法。所以join方法在阻塞的时候,会释放同步控制器,这是与sleep()方法不同的一点!
  • wait()方法,Object类的实例方法,当实例对象作为同步监视器时,在同步方法或者同步代码块中,调用同步监视器的wait()方法,使当前线程阻塞xxx毫秒+xxx纳秒或者阻塞被唤醒;同时当前线程释放同步监视器
  • notify()、notifyall(),Object类的实例方法,当实例对象作为同步监视器时,在同步方法或者同步代码中,调用同步监视器的notify()方法,随机唤醒一个被同步监视器wait的线程;调用同步监视器的notifyall()方法,唤醒所有被同步监视器wait的线程(虽然线程不再是wait状态,但是线程在抢同步监视器的时候,依然存在阻塞现象)
  • 注意:wait()、notify()、notifyall()必须在同步代码块或者同步方法中调用,并且调用实例对象,必须为当前同步代码块或者同步方法的同步监视器!!!其实这三个方法,就是起到了通过同步监视器进行线程间通信的作用!!!
  • wait()、notify()、notifyall()三个方法,主要就是为了解决,当一个线程中的某个执行条件依赖与另一个线程的执行结果的场景,并且两个线程在同一个同步监视器中;如线程A挂起等待线程B执行完毕再继续执行,并且线程A和线程B的执行共用一个同步监视器;如果线程A使用sleep()方法阻塞,不释放同步监视器,则线程B永远获取不到同步监视器,线程B永远得不到执行,这样线程A和线程B就发生了死锁。如果线程A使用wait方法阻塞,并释放同步监视器,这样线程B就会抢占到同步监视器并执行,执行后调用notify方法唤醒线程A,线程A脱离wait状态并再次抢占到同步监视器并继续执行!!!

源码分析:

public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

Ps:join参数为0的时候,会调用线程实例(因为这个同步方法的同步监视器为线程实例)的wait(0)方法,阻塞当前线程;当线程实例执行完成,在线程结束的时候,会调用线程实例的notifyAll()方法,用来及时的恢复join状态;这时在判断线程实例isAlive(),退出while循环,阻塞结束!参数为long millis的时候,原理类似!

对于线程退出中的notifyAll()调用说明(下面是thread.cpp的源码,关注ensure_join()函数):

3.5 isAlive()方法(线程存活判断):

public final native boolean isAlive();

Thread类的实例方法,通过isAlive()方法,可以获取实例线程的线程状态是否为存活状态,运行和阻塞均返回true,结束或者异常返回false!

3.6 start()、run()方法(线程启动):

public synchronized void start()
public void run()
  • Thread类的实例方法,start()为线程启动入口;
  • Thread类的实例方法,run()是Thread类从Runnable接口继承过来的,最终调用的也是构造方法中传入的Runnable实例的run()方法,但是调用run()方法不是启动线程,而是在当前线程中执行run()方法!

3.7 interrupt()、interrupted()、isInterrupted()方法(线程打断):

public void interrupt() 
public static boolean interrupted() 
public boolean isInterrupted()
  • Thread类的实例方法,interrupt()方法为线程实例设置interrupt打断标记,然后线程实例在判断打断标记的时候,就会执行打断逻辑!
  • Thread类的实例方法,isInterrupted()方法,判断线程实例的打断标记,但并不清除打断标记!
  • Thread类的类方法,interrupted() 方法,判断当前线程的打断标记,并清除打断标记!

3.8 setDaemon(boolean on)、isDaemon()方法(守护线程):

public final void setDaemon(boolean on)
public final boolean isDaemon()
  • Thread类的实例方法,在线程实例调用start()方法前,调用setDaemon()将线程实例设置为守护线程
  • Thread类的实例方法,判断当前线程释放为守护线程
  • 守护线程:当Jvm中无正在执行的非守护线程时,Jvm会自动结束,随之未完成的守护线程也同步结束!
public class ThreadCase 
{
	public static void main(String args[]) throws InterruptedException
	{
		System.out.println("main " + Thread.currentThread().getName());
		
		MainThread main = new MainThread();
		Thread mainThread = new Thread(main);
		mainThread.start();
		Thread.sleep(10000);
		/*非守护进程都执行完毕,Jvm退出*/
		System.out.println("Jvm Finish!!!");
		
	}
}

class MainThread implements Runnable
{

	@Override
	public void run() 
	{
		try
		{
			/*启动守护线程*/
			DaemonThread daemon = new DaemonThread();
			Thread daemonThread = new Thread(daemon);
			daemonThread.setDaemon(true);
			daemonThread.start();		
			Thread.sleep(5000);
			System.out.println("MainThread Finish");
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	
}

class DaemonThread implements Runnable
{

	@Override
	public void run()
	{
		try
		{
			/*守护线程while(1)循环*/
			while(true)
			{
				System.out.println("DaemonThread... ");
				Thread.sleep(1000);
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}

		
	}
	
}

执行结果:

3.9 setPriority(int newPriority)、getPriority()方法(设置线程优先级):

public final void setPriority(int newPriority)
public final int getPriority()
  • Thread类的实例方法,setPriority()方法设置线程实例的优先级,最大值MAX_PRIORITY=10,最小值MIN_PRIORITY=1,默认的线程优先级为父线程的优先级,main方法的优先级为默认优先级NORM_PRIORITY=5
  • Thread类的实例方法,getPriority()方法,获取线程实例的优先级
  • 线程优先级依赖于操作系统的实现,所以不同操作系统可能策略不一样,过度的依赖线程优先级可能造成移植性变差!

3.10 setName(String name)、getName()方法(设置线程名):

public final synchronized void setName(String name)
public final String getName()
  • Thread类的实例方法,setName()方法设置线程实例的名字
  • Thread类的实例方法,getName()方法获取线程实例的名字
  • 不同线程,可以设置相同的线程名字,并没有要求线程名字唯一!
  • 在Thread类构造方法中也可以设置线程名字,构造方法中默认的线程名字格式为:Thread-线程个数
    /* For autonumbering anonymous threads. */
    private static int threadInitNumber;
    private static synchronized int nextThreadNum() {
        return threadInitNumber++;
    }

    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }

3.11 线程分组:

Thread提供线程分组能力,用来统一管理一类线程,如果需要设置线程组必须通过Thread构造方法中设置 ,不设置线程组为默认线程组(Main方法线程的线程组)!

public Thread(ThreadGroup group, Runnable target)
public Thread(ThreadGroup group, String name)
public Thread(ThreadGroup group, Runnable target, String name)
public Thread(ThreadGroup group, Runnable target, String name, long stackSize)

private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }

        this.name = name;

        Thread parent = currentThread();
        SecurityManager security = System.getSecurityManager();
        if (g == null) {
            /* Determine if it's an applet or not */

            /* If there is a security manager, ask the security manager
               what to do. */
            if (security != null) {
                g = security.getThreadGroup();
            }

            /* If the security doesn't have a strong opinion of the matter
               use the parent thread group. */
            if (g == null) {
                g = parent.getThreadGroup();
            }
        }
......
}

ThreadGroup类为线程组类,构造方法如下:

public ThreadGroup(String name)
public ThreadGroup(ThreadGroup parent, String name)

ThreadGroup类中常用方法:

/*设置线程组的最大线程优先级*/
public final void setMaxPriority(int pri)

/*设置线程组为守护线程组,当线程组中最后一个线程执行完成或最后一个线程被销毁后,线程组自动销毁*/
public final void setDaemon(boolean daemon)

/*获取线程组名字*/
public final String getName()

/*获取父线程组实例*/
public final ThreadGroup getParent() 

/*获取线程组线程优先级*/
public final int getMaxPriority()

/*判断线程组是否为守护线程组*/
public final boolean isDaemon()

/*中断线程组中的所有线程*/
public final void interrupt()

/*销毁线程组*/
public final void destroy()

/*检测当前线程组是否被销毁*/
public synchronized boolean isDestroyed()

/*获取线程组中存活线程个数*/
public int activeCount()

/*获取线程组中的所有线程*/
public int enumerate(Thread list[])

Thread类中的getThreadGroup()、activeCount()、enumerate(Thread tarray[])方法():

public final ThreadGroup getThreadGroup()
public static int activeCount()
public static int enumerate(Thread tarray[])
  • Thread类的实例方法,getThreadGroup()获取线程实例的线程组
  • Thread类的类方法,activeCount()获取当前线程所属线程组中存活线程的个数
  • Thread类的类方法,enumerate(Thread tarray[])获取当前线程所属线程组中所有线程

3.12 stop()、stop(Throwable obj)、destroy()方法(停止线程):

不推荐使用,使用不当容易造成死锁,已经被废弃!推荐使用interrupt()实现线程停止的能力!

public final void stop()
public final synchronized void stop(Throwable obj)
public void destroy()
  • Thread类的实例方法,stop()方法停止线程实例
  • Thread类的实例方法,stop(Throwable obj)方法停止线程实例,并抛出obj异常
  • Thread类的实例方法,destroy()方法未实现,为空方法,无任何能力!

3.13 suspend()、resume()方法(线程挂起及恢复):

不推荐使用,使用不当容易造成死锁,已经被废弃!推荐使用wait()、notify()、notifyall()方法实现线程的挂起及恢复!

public final void suspend()
public final void resume()

Thread类的实例方法,suspend()方法使线程实例挂起,然后线程阻塞等待resume唤醒!

Thread类的实例方法,resume()方法使挂起的线程实例,恢复运行!

3.14 Thread类的构造方法:

    //设置runnalbe类
    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
    //设置线程分组,runnable类
    public Thread(ThreadGroup group, Runnable target) {
        init(group, target, "Thread-" + nextThreadNum(), 0);
    }
    //设置线程名,runnable类
    public Thread(Runnable target, String name) {
        init(null, target, name, 0);
    }

    //设置线程名,线程分组,runnable类
    public Thread(ThreadGroup group, Runnable target, String name) {
        init(group, target, name, 0);
    }

    //设置线程名,线程分组,runnable类,stackSize(默认为0)
    public Thread(ThreadGroup group, Runnable target, String name,
                  long stackSize) {
        init(group, target, name, stackSize);
    }
    //未设置runnable类的Thread构造方法,run()方法为空方法
    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }
    public Thread(String name) {
        init(null, null, name, 0);
    }
    public Thread(ThreadGroup group, String name) {
        init(group, null, name, 0);
    }
  • Thread构造方法主要设置runnable类、线程分组、线程名(默认线程名为"Thread-" + nextThreadNum())
  • 通过未设置runnable类的构造方法实例化的线程实例,run()方法为空方法!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值