JavaSE:多线程

1、多线程定义

进程:
		正在运行的程序,是系统进行资源分配和调用的独立单位。
		每一个进程都有它自己的内存空间和系统资源。
线程:
		是进程中的单个顺序控制流,是一条执行路径
		一个进程如果只有一条执行路径,则称为单线程程序。
		一个进程如果有多条执行路径,则称为多线程程序。
		是程序使用CPU的最基本单位	

多线程意义:
多线程的存在,不是提高程序的执行速度。其实是为了提高应用程序的使用率。
程序的执行其实都是在抢CPU的资源,CPU的执行权。
多个进程是在抢这个资源,而其中的某一个进程如果执行路径比较多,就会有更高的几率抢到CPU的执行权。
我们是不敢保证哪一个线程能够在哪个时刻抢到,所以线程的执行有随机性。

并行和并发:
		并行是逻辑上同时发生,指在某一个时间内同时运行多个程序。
		并发是物理上同时发生,指在某一个时间点同时运行多个程序。

Java程序的运行原理:
 		由java命令启动JVM,JVM启动就相当于启动了一个进程。
 		接着有该进程创建了一个主线程去调用main方法。

2、继承Thread类

2.1 方式1:继承Thread类。

步骤	A:自定义类MyThread继承Thread类。
		B:MyThread类里面重写run()
		  为了区分哪些代码能够被线程执行,java提供了Thread类中的run()用来包含那些被线程执行的代码。
		C:创建对象
		D:启动线程

2.2 线程常用方法

public final String getName():获取线程的名称。
public final void setName(String name):设置线程的名称
public static Thread currentThread():返回当前正在执行的线程对象
	例:Thread.currentThread().getName()  //获取当前线程对象的线程名称

public final int getPriority():返回线程对象的优先级
public final void setPriority(int newPriority):更改线程的优先级。 
注意:
		线程默认优先级是5。
		线程优先级的范围是:1-10。
		线程优先级高仅仅表示线程获取的 CPU时间片的几率高,但是要在次数比较多,或者多次运行的时候才能看到比较好的效果。

线程休眠(暂停)
	public static void sleep(long millis):单位是毫秒
线程加入
	public final void join():等待该线程终止后面的才执行,必须放在strart()之后
线程礼让
		public static void yield():暂停当前正在执行的线程对象,并执行其他线程。 
线程守护 (终止退出jvm)
		public final void setDaemon(boolean on):将该线程标记为守护线程或用户线程。
		当正在运行的线程都是守护线程时,Java 虚拟机退出。 
		该方法必须在启动线程前调用。 在start()之前
线程中断
		public final void stop():让线程停止,过时了,但是还可以使用。
		public void interrupt():中断线程。 把线程的状态终止,并抛出一个InterruptedException。

import java.util.Date;

public class MyThread extends Thread {
	public MyThread() {
		// TODO Auto-generated constructor stub
	}
	
	public MyThread(String name) {
		// TODO Auto-generated constructor stub
		super(name);
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.run();
		for(int x=0;x<10;x++){
			System.out.println(getName()+":"+x+",日期 "+new Date());
			//加入线程休眠
			try {
				sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			Thread.yield();
			
		}
	}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class ThreadDemo {
	public static void main(String[] args) {
		System.out.println(Thread.currentThread().getName());
		
//		 * 方式1:继承Thread类。
//		 * 步骤	A:自定义类MyThread继承Thread类。
//		 * 		B:MyThread类里面重写run()
//		 * 		C:创建对象
//		 * 		D:启动线程	
		MyThread mt1=new MyThread();
		MyThread mt2=new MyThread();	
		MyThread mt3=new MyThread();
		mt1.setName("mt1:");
		mt2.setName("mt2:");
		mt3.setName("mt3:");
		
		System.out.println(mt1.getPriority());
		System.out.println(mt2.getPriority());		
		//mt1.setPriority(10)
		
		mt1.start();
		mt2.start();
		mt3.start();
		
	}
}

3、实现Runnable接口

3.1 方式2:实现Runnable接口

步骤:
		A:自定义类MyRunnable实现Runnable接口
		B:重写run()方法
		C:创建MyRunnable类的对象
		D:创建Thread类的对象,并把C步骤的对象作为构造参数传递
实现接口方式的好处
	可以避免由于Java单继承带来的局限性。
	适合多个相同程序的代码去处理同一个资源的情况,把线程同程序的代码,数据有效分离,较好的体现了面向对象的设计思想。

3.2 同步机制

方式一:同步代码块
把多条语句操作共享数据的代码给包成一个整体,让某个线程在执行的时候,别人不能来执行。
同步代码块:
		synchronized(对象){
			需要同步的代码;
		}
这里的锁对象可以是任意对象。
如:private Object obj = new Object();
注意:
		同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。
		多个线程必须是同一把锁。

方式二:同步方法
		把同步加在方法上。
		这里的锁对象是this
如:private static synchronized void Mysynchronized() {}

public class Mysynchronized implements Runnable {
	private static int tickets=100;
	private Object obj=new Object();
	private int x=0;
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true){
			if(x%2==0){
				synchronized(obj){
					if(tickets>0){
						try {
							Thread.sleep(100);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						System.out.println(Thread.currentThread().getName()+"正在出售第:"+tickets+"张票");
						tickets--;
					}
				}
			}else {
				sellTicket();
			}
			x++;
		}
	}
	
	
	
	private static synchronized void sellTicket(){
		if(tickets>0){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+ "正在出售第" + (tickets--) + "张票 ");
			
		}
	}
	
public class synchronizedDemo {
	public static void main(String[] args) {
		Mysynchronized  ms=new Mysynchronized();
		Thread t1=new Thread(ms,"窗口1");
		Thread t2=new Thread(ms,"窗口2");
		Thread t3=new Thread(ms,"窗口3");
		
		t1.start();
		t2.start();
		t3.start();
				
	}		
}

4、等待唤醒机制

Object类中提供了三个方法:
		wait():等待
		notify():唤醒单个线程
		notifyAll():唤醒所有线程
		这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。
		所以,这些方法必须定义在Object类中,而不定义在Thread类中

sleep()和wait()方法的区别
sleep():必须指时间;不释放锁。
wait():可以不指定时间,也可以指定时间;释放锁。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyLock implements Runnable {
	private static int tickets=100;
	private Object obj=new Object();
	
	private Lock lock=new ReentrantLock();
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true){
			synchronized(obj){
				//加锁
				lock.lock();
				try{
					if(tickets>0){
						try {
							Thread.sleep(100);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						System.out.println(Thread.currentThread().getName()+"正在出售第:"+tickets+"张票");
							tickets--;
						}
				}finally{
					//释放锁
					lock.unlock();
				}
			}
		}
	}
	
}

public class LockDemo {
	public static void main(String[] args) {
		MyLock  ms=new MyLock();
		Thread t1=new Thread(ms,"窗口1");
		Thread t2=new Thread(ms,"窗口2");
		Thread t3=new Thread(ms,"窗口3");
		
		t1.start();
		t2.start();
		t3.start();
				
	}
}

5、线程组

线程组: 把多个线程组合到一起。
它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。

线程组里面的方法:public final ThreadGroup getThreadGroup()
线程组里面的方法:public final String getName()

//通过组名称设置后台线程,表示该组的线程都是后台线程
tg.setDaemon(true);

public class MyRunnable implements Runnable {
	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int x=0;x<10;x++){
			System.out.println(Thread.currentThread().getName()+":"+x);
		}
	}
}

public class ThreadGroupDemo {
	public static void main(String[] args) {
		//创建线程组
		ThreadGroup tg1=new ThreadGroup("这是第一个线程组");
		
		MyRunnable mr=new MyRunnable();
		Thread t1=new Thread(tg1,mr, "林青霞");
		Thread t2=new Thread(tg1,mr, "张曼玉");
		
		System.out.println(t1.getThreadGroup().getName());//这是第一个线程组
		t1.start();
		t2.start();
		
		//ThreadGroup tg2=new ThreadGroup("这是第二个线程组");	
	}
}

6、线程池

线程池的好处:
线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。
程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。
而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。

public static ExecutorService newCachedThreadPool():创建一个线程池对象
public static ExecutorService newFixedThreadPool(int nThreads):制定数量线程池
public static ExecutorService newSingleThreadExecutor():单一线程池

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

public class MyRunnable implements Runnable {
	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int x=0;x<10;x++){
			System.out.println(Thread.currentThread().getName()+":"+x);
		}
	}
}

public class ExecutorsDemo {
	public static void main(String[] args) {
		ExecutorService pool=Executors.newFixedThreadPool(2);
		
		pool.submit(new MyRunnable());
		pool.submit(new MyRunnable());
		
		pool.shutdown();
		
	}
}

7、匿名类调用线程

public class NoNameThreadDemo {
	public static void main(String[] args) {
		
		//继承Thread
		new Thread(){
			@Override
			public void run() {
				for (int x = 0; x < 10; x++) {
					System.out.println(Thread.currentThread().getName() + ":"
							+ x);
				}
			}
		}.start();
		
		//实现Runnable
		new Thread(new Runnable(){
			@Override
			public void run() {
				for (int x = 0; x < 10; x++) {
					System.out.println(Thread.currentThread().getName() + ":"
							+ x);
				}
			}
		}){
			
		}.start();
			
	
		
	}
}

8、TimerTask定时任务

class DeleteFolder extends TimerTask {

	@Override
	public void run() {
		File srcFolder = new File("demo");
		deleteFolder(srcFolder);
	}

	// 递归删除目录
	public void deleteFolder(File srcFolder) {
		File[] fileArray = srcFolder.listFiles();
		if (fileArray != null) {
			for (File file : fileArray) {
				if (file.isDirectory()) {
					deleteFolder(file);
				} else {
					System.out.println(file.getName() + ":" + file.delete());
				}
			}
			System.out.println(srcFolder.getName() + ":" + srcFolder.delete());
		}
	}
}

public class TimerDemo {
	public static void main(String[] args) throws ParseException {
		Timer t = new Timer();

		String s = "2014-11-27 15:45:00";
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date d = sdf.parse(s);

		t.schedule(new DeleteFolder(), d);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值