线程:整理

一:线程概述

1,进程:正在运行的程序,是系统进行资源分配和调用的独立单位。每一个进程都有它自己的内存空间和系统资源。

2,线程:是进程中的单个顺序控制流,是一条执行路径一个进程如果只有一条执行路径,则称为单线程程序。一个进程如果有多条执行路径,则称为多线程程序。

二:线程的实现:

 1,方式一:

编写一个类继承Thread类

重写run()方法

线程

线程类:

public class MyThread extends Thread {
	@Override
	public void run() {
		for (int x = 0; x < 200; x++) {
			System.out.println(x);
		}
	}
}

测试类:

public class MyThreadDemo {
	public static void main(String[] args) {
		MyThread my1 = new MyThread();
		MyThread my2 = new MyThread();
		my1.start();
		my2.start();
	}
}

a,注意:

           run和start的区别:

                run():仅仅是封装被线程执行的代码,直接调用是普通方法

                start():首先启动了线程,然后再由jvm去调用该线程的run()方法。

b,为什么要重写run方法

            不是类中的所有代码都需要被线程执行的。而这个时候,为了区分哪些代码能够被线程执行,java提供了Thread                 类中的run()用来包含那些被线程执行的代码。

            C:创建对象

            D:启动线程

c,线程名的获取和设置

         设置名称: public final String setName()或者构造方法来设置线程的名称。

          获取名称:

               public final String getName():获取线程的名称。

               public static Thread currentThread():返回当前正在执行的线程对象

d,线程优先级

      线程优先级默认为5,范围为1至10;

通过:

           public final int getPriority()

获取优先级

通过:

           public final void setPriority(int newPriority)

设置优先级别

e,线程控制

 线程休眠
         public static void sleep(long millis)

public class ThreadSleepDemo {
	public static void main(String[] args) {
		ThreadSleep ts1 = new ThreadSleep();
		ThreadSleep ts2 = new ThreadSleep();
		ThreadSleep ts3 = new ThreadSleep();
 
		ts1.setName("林青霞");
		ts2.setName("林志玲");
		ts3.setName("林志颖");
 
		ts1.start();
		ts2.start();
		ts3.start();
	}
}
public class ThreadSleep extends Thread {
	@Override
	public void run() {
		for (int x = 0; x < 100; x++) {
			System.out.println(getName() + ":" + x + ",日期:" + new Date());
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}


        
  加入线程
        public final void join():等待该线程终止。 
        

public class ThreadJoinDemo {
	public static void main(String[] args) {
		ThreadJoin tj1 = new ThreadJoin();
		ThreadJoin tj2 = new ThreadJoin();
		ThreadJoin tj3 = new ThreadJoin();
 
		tj1.setName("李渊");
		tj2.setName("李世民");
		tj3.setName("李元霸");
 
		tj1.start();
		try {
			tj1.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		tj2.start();
		tj3.start();
	}
}
public class ThreadJoin extends Thread {
	@Override
	public void run() {
		for (int x = 0; x < 100; x++) {
			System.out.println(getName() + ":" + x);
		}
	}
}


  礼让线程
        public static void yield():暂停当前正在执行的线程对象,并执行其他线程。 
        让多个线程的执行更和谐,但是不能靠它保证一人一次。

public class ThreadYieldDemo {
	public static void main(String[] args) {
		ThreadYield ty1 = new ThreadYield();
		ThreadYield ty2 = new ThreadYield();
 
		ty1.setName("林青霞");
		ty2.setName("刘意");
 
		ty1.start();
		ty2.start();
	}
}
public class ThreadYield extends Thread {
	@Override
	public void run() {
		for (int x = 0; x < 100; x++) {
			System.out.println(getName() + ":" + x);
			Thread.yield();
		}
	}
}


  守护线程:
         public final void setDaemon(boolean on):将该线程标记为守护线程或用户线程。
         当正在运行的线程都是守护线程时,Java 虚拟机退出。 该方法必须在启动线程前调用。 
         游戏:坦克大战。

public class ThreadDaemonDemo {
	public static void main(String[] args) {
		ThreadDaemon td1 = new ThreadDaemon();
		ThreadDaemon td2 = new ThreadDaemon();
 
		td1.setName("关羽");
		td2.setName("张飞");
 
		// 设置收获线程
		td1.setDaemon(true);
		td2.setDaemon(true);
 
		td1.start();
		td2.start();
 
		Thread.currentThread().setName("刘备");
		for (int x = 0; x < 5; x++) {
			System.out.println(Thread.currentThread().getName() + ":" + x);
		}
	}
}
 
public class ThreadDaemon extends Thread {
	@Override
	public void run() {
		for (int x = 0; x < 100; x++) {
			System.out.println(getName() + ":" + x);
		}
	}
}


   线程中断: 
          public final void stop():让线程停止,过时了,但是还可以使用。
          public void interrupt():中断线程。 把线程的状态终止,并抛出一个InterruptedException。

public class ThreadStopDemo {
	public static void main(String[] args) {
		ThreadStop ts = new ThreadStop();
		ts.start();
 
		// 你超过三秒不醒过来,我就干死你
		try {
			Thread.sleep(3000);
			// ts.stop();
			ts.interrupt();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
 
public class ThreadStop extends Thread {
	@Override
	public void run() {
		System.out.println("开始执行:" + new Date());
 
		// 我要休息10秒钟,亲,不要打扰我哦
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			// e.printStackTrace();
			System.out.println("线程被终止了");
		}
 
		System.out.println("结束执行:" + new Date());
	}
}

2,线程实现方式二

    a,步骤

  1.                      创建自定义类MyRunnable,实现Runnable接口;
  2.                      重写run()方法
  3.                      创建MyRunnable对象
  4.                      创建Thread类对象,将MyRunnable对象作为形参进行传递
  5.                      启动线程

代码:

public class RunnableDemo {
 
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//线程实现的第二种方法
		//创建线程对象
		MyRunnable mr1 = new MyRunnable();
		//创建Thread对象,将mr1作为形参作为传递
		/*
		Thread t1 = new Thread (mr1);
		Thread t2 = new Thread (mr1);
		t1.setName("线程一");
		t1.setName("线程二");
		*/
		Thread t1 = new Thread (mr1,"线程一");
		Thread t2 = new Thread (mr1,"线程二");
		t1.start();
		t2.start();
	}
 
}
class MyRunnable implements Runnable{
	public void run(){
		System.out.println(Thread.currentThread().getName()+":"+"yangjinbiao");
	}
}

三:线程安全

1,线程的生命周期

2,产生线程不安全的原因?

           :是否是多线程环境 ;是否有共享数据 ;是否有多条语句操作共享数据 。

3,解决线程安全:加锁(synchronized )

            a,同步代码块

                       格式synchronized(对象){需要同步的代码};

                   注意:可以是任意对象,但是必须使用的是同一个对象。

           b,同步方法

                         锁对象为;this

          c,静态同步方法

                        锁对象:类的字节码文件对象。

           d:等待唤醒机制

                           Object类中提供了三个方法:

                                   wait():等待

                                   notify():唤醒单个线程

                                   notifyAll():唤醒所有线程

4,生产消费者模式(等待唤醒机制)

          共享的资源:

共同资源
public class Student {
	private String name;
	private int age;
	private boolean flag; // 默认情况是没有数据,如果是true,说明有数据
 
	public synchronized void set(String name, int age) {
		// 如果有数据,就等待
		if (this.flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
 
		// 设置数据
		this.name = name;
		this.age = age;
 
		// 修改标记
		this.flag = true;
		this.notify();
	}
 
	public synchronized void get() {
		// 如果没有数据,就等待
		if (!this.flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
 
		// 获取数据
		System.out.println(this.name + "---" + this.age);
 
		// 修改标记
		this.flag = false;
		this.notify();
	}
}

生产者:

public class SetThread implements Runnable {
 
	private Student s;
	private int x = 0;
 
	public SetThread(Student s) {
		this.s = s;
	}
 
	@Override
	public void run() {
		while (true) {
			if (x % 2 == 0) {
				s.set("林青霞", 27);
			} else {
				s.set("刘意", 30);
			}
			x++;
		}
	}
}

消费者:


public class GetThread implements Runnable {
	private Student s;
 
	public GetThread(Student s) {
		this.s = s;
	}
 
	@Override
	public void run() {
		while (true) {
			s.get();
		}
	}

测试:


public class StudentDemo {
	public static void main(String[] args) {
		//创建资源
		Student s = new Student();
		
		//设置和获取的类
		SetThread st = new SetThread(s);
		GetThread gt = new GetThread(s);
 
		//线程类
		Thread t1 = new Thread(st);
		Thread t2 = new Thread(gt);
 
		//启动线程
		t1.start();
		t2.start();
	}
}

四:线程池(第三种创建线程实现方式)

1,线程池的好处: 

             线程池的好处:线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对               象来使用。

2,创建线程池步骤:

          A:创建一个线程池对象,控制要创建几个线程对象:public static ExecutorService newFixedThreadPool(int nThreads)
          B:这种线程池的线程可以执行:
             可以执行Runnable对象或者Callable对象代表的线程
              做一个类实现Runnable接口。
          C:调用如下方法即可
              Future<?> submit(Runnable task)
           <T> Future<T> submit(Callable<T> task)
       D:我就要结束,可以吗?
          可以。

public class ExecutorsDemo {
	public static void main(String[] args) {
		// 创建一个线程池对象,控制要创建几个线程对象。
		// public static ExecutorService newFixedThreadPool(int nThreads)
		ExecutorService pool = Executors.newFixedThreadPool(2);
 
		// 可以执行Runnable对象或者Callable对象代表的线程
		pool.submit(new MyRunnable());
		pool.submit(new MyRunnable());
 
		//结束线程池
		pool.shutdown();
	}
}
 
public class MyRunnable implements Runnable {
 
	@Override
	public void run() {
		for (int x = 0; x < 100; x++) {
			System.out.println(Thread.currentThread().getName() + ":" + x);
		}
	}
 
}

3,线程的第三种实现方案-实现Callable<Integer> 接口:(使用线程池实现)

public class CallableDemo {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		// 创建线程池对象
		ExecutorService pool = Executors.newFixedThreadPool(2);
 
		// 可以执行Runnable对象或者Callable对象代表的线程
		Future<Integer> f1 = pool.submit(new MyCallable(100));
		Future<Integer> f2 = pool.submit(new MyCallable(200));
 
		// V get()
		Integer i1 = f1.get();
		Integer i2 = f2.get();
 
		System.out.println(i1);
		System.out.println(i2);
 
		// 结束
		pool.shutdown();
	}
}

线程类:


public class MyCallable implements Callable<Integer> {
 
	private int number;
 
	public MyCallable(int number) {
		this.number = number;
	}
 
	@Override
	public Integer call() throws Exception {
		int sum = 0;
		for (int x = 1; x <= number; x++) {
			sum += x;
		}
		return sum;
	}

 

4,创建线程池的方式;

①. newFixedThreadPool(int nThreads)

创建一个固定长度的线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程规模将不再变化,当线程发生未预期的错误而结束时,线程池会补充一个新的线程。

②. newCachedThreadPool()

创建一个可缓存的线程池,如果线程池的规模超过了处理需求,将自动回收空闲线程,而当需求增加时,则可以自动添加新线程,线程池的规模不存在任何限制。

③. newSingleThreadExecutor()

这是一个单线程的Executor,它创建单个工作线程来执行任务,如果这个线程异常结束,会创建一个新的来替代它;它的特点是能确保依照任务在队列中的顺序来串行执行。

④. newScheduledThreadPool(int corePoolSize)

创建了一个固定长度的线程池,而且以延迟或定时的方式来执行任务,类似于Timer。

五:线程组

public class ThreadGroupDemo {
	public static void main(String[] args) {
		// method1();

		// 我们如何修改线程所在的组呢?
		// 创建一个线程组
		// 创建其他线程的时候,把其他线程的组指定为我们自己新建线程组
		method2();

		// t1.start();
		// t2.start();
	}

	private static void method2() {
		// ThreadGroup(String name)
		ThreadGroup tg = new ThreadGroup("这是一个新的组");

		MyRunnable my = new MyRunnable();
		// Thread(ThreadGroup group, Runnable target, String name)
		Thread t1 = new Thread(tg, my, "林青霞");
		Thread t2 = new Thread(tg, my, "刘意");
		
		System.out.println(t1.getThreadGroup().getName());
		System.out.println(t2.getThreadGroup().getName());
		
		//通过组名称设置后台线程,表示该组的线程都是后台线程
		tg.setDaemon(true);
	}

	private static void method1() {
		MyRunnable my = new MyRunnable();
		Thread t1 = new Thread(my, "林青霞");
		Thread t2 = new Thread(my, "刘意");
		// 我不知道他们属于那个线程组,我想知道,怎么办
		// 线程类里面的方法:public final ThreadGroup getThreadGroup()
		ThreadGroup tg1 = t1.getThreadGroup();
		ThreadGroup tg2 = t2.getThreadGroup();
		// 线程组里面的方法:public final String getName()
		String name1 = tg1.getName();
		String name2 = tg2.getName();
		System.out.println(name1);
		System.out.println(name2);
		// 通过结果我们知道了:线程默认情况下属于main线程组
		// 通过下面的测试,你应该能够看到,默任情况下,所有的线程都属于同一个组
		System.out.println(Thread.currentThread().getThreadGroup().getName());
	}
}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章