Java-多线程(上)

进程与线程的概念

进程:操作系统中一个程序的执行周期称为一个进程。

DOS系统的时代,由于其本身就是一个单进程的操作系统,所以在同一时间段上只能够有一个程序执行。后来发展到winodws系统后,我们发现多个程序可以同时执行,所以windows是一个多进程的操作系统。

线程:一个程序同时执行多个任务。通常,每一个任务就称为一个线程。与进程相比较,线程更"轻量级",创建、撤销一个线程比启动一个新进程开销要小的多。没有进程就没有线程,进程一旦终止,其内的线程也将不复存在。

多进程与多线程区别:本质区别在于,每个进程拥有自己的一整套变量,而线程则共享数据。共享变量使得线程之
间的通信比进程之间通信更有效、更方便。

那么,多线程表现在哪里呢?

在实际应用中,多线程非常有用。例如,一个浏览器应用可以同时下载多个图片、音乐;一个Web服务器需要同时处理多个并发的请求。这些都是多线程的应用。

高并发:访问的线程量非常非常高。

高并发带来的问题:服务器内存不够用,无法处理新的请求。


Java多线程实现

方法1:继承Thread类实现多线程

范例:

class MyThread extends Thread { // 线程主体类
	private String title;

	public MyThread(String title) {
		this.title = title;
	}

	@Override
	public void run() { // 所有线程从此处开始执行
		for (int i = 0; i < 10; i++) {
			System.out.println(this.title + ",i = " + i);
		}
	}
}

正确启动多线程使用start()方法而不是run()!!!

MyThread myThread1 = new MyThread("thread1") ;

myThread1.start();

 

方法2Runnable接口实现多线程

Thread类的核心功能是进行线程的启动。如果一个类为了实现多线程直接去继承Thread类就会有但继承局限。在java中又提供有另外一种实现模式:Runnable接口。

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

范例:

class MyThread implements Runnable { // 线程主体类
	private String title;

	public MyThread(String title) {
		this.title = title;
	}

	@Override
	public void run() { // 所有线程从此处开始执行
		for (int i = 0; i < 10; i++) {
			System.out.println(this.title + ",i = " + i);
		}
	}
}

范例:使用匿名内部类进行Runnable对象创建

public class TestDemo {
	public static void main(String[] args) {
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("Hello World");
			}
		}).start();
	}
}

范例:使用Lamdba表达式进行Runnable对象创建

public class TestDemo {
	public static void main(String[] args) {
		Runnable runnable = () -> System.out.println("Hello World");
		new Thread(runnable).start();
	}
}

ThreadRunnable区别


范例:使用Thread实现数据共享(产生若干线程进行同一数据的处理操作)

class MyThread extends Thread {
	private int ticket = 10; // 一共10张票

	@Override
	public void run() {
		while (this.ticket > 0) {
			System.out.println("剩余票数:" + this.ticket--);
		}
	}
}

public class TestDemo {
	public static void main(String[] args) {
		new MyThread().start();
		new MyThread().start();
		new MyThread().start();
	}
}

此时启动三个线程实现卖票处理。结果变为了卖各自的票。

范例:使用Runnable实现共享

class MyThread implements Runnable {
	private int ticket = 10; // 一共10张票

	@Override
	public void run() {
		while (this.ticket > 0) {
			System.out.println("剩余票数:" + this.ticket--);
		}
	}
}

public class TestDemo {
	public static void main(String[] args) {
		MyThread mt = new MyThread();
		new Thread(mt).start();
		new Thread(mt).start();
	}
}

Runnable实现的多线程的程序类可以更好的描述出程序共享的概念。


方法3Callable实现多线程:

@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}

        Runnable中的run()方法没有返回值,它的设计也遵循了主方法的设计原则:线程开始了就别回头。但是很多时候需要一些返回值,例如某些线程执行完成后可能带来一些返回结果,这种情况下就只能利用Callable来实现多线程。

class MyThread implements Callable<String> {
	private int ticket = 10; // 一共10张票

	@Override
	public String call() throws Exception {
		while (this.ticket > 0) {
			System.out.println("剩余票数:" + this.ticket--);
		}
		return "票卖完了,下次吧。。。";
	}
}

public class TestDemo {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		FutureTask<String> task = new FutureTask<>(new MyThread());
		new Thread(task).start();
		new Thread(task).start();
		System.out.println(task.get());
	}
}

Thread类中提供有如下的线程名称方法:

 

获取当前线程名字方式:Thread.currentThread().getName();

通过以上程序我们发现,主方法本身就是一个线程,所有的线程都是通过主线程创建并启的。

疑问:进程在哪?

实际上每当使用了java命令去解释程序的时候,都表示启动了一个新的JVM进程。而主方法只是这个进程上的一个线程而已。


线程的五种状态之间的相互转换


线程休眠(sleep方法)

线程休眠:指的是让线程暂缓执行一下,等到了预计时间之后再恢复执行。

 

线程让步(yield()方法)

暂停当前正在执行的线程对象,并执行其他线程。

注意,调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的。

 

join()方法(插队方法)

等待该线程终止。意思就是如果在主线程中调用该方法时就会让主线程休眠,让调用该方法的线程run方法先执行完毕之后在开始执行主线程。

 

线程停止

多线程中有三种方式可以停止线程。

1. 设置标记位,可以使线程正常退出。

2. 使用stop方法强制使线程退出,但是该方法不太安全所以已经被废弃了。

3. 使用Thread类中的一个 interrupt() 可以中断线程。

 

线程优先级

线程的优先级指的是,线程的优先级越高越有可能先执行,但仅仅是有可能而已。

设置优先级 public final void setPriority(int newPriority)

取得优先级 public final int getPriority()

1. 最高优先级:public final static int MAX_PRIORITY = 10;

2. 中等优先级:public final static int NORM_PRIORITY = 5;

3. 最低优先级:public final static int MIN_PRIORITY = 1;

线程是有继承关系的,比如当A线程中启动B线程,那么BA的优先级将是一样的。

原文地址:https://www.cnblogs.com/yongtaochang/p/13615349.html