Java多线程笔记 多学多练(一)

                                  java多线程学习笔记 

  写在前言,不管学习什么知识点,自己还是要边学边用。

  在学习的过程中把一些自己认为重要的知识点记下来,看书只是为了看明白,吸收为自己的东西还需要自己多练练。然后自己做个总结,隔一段时间翻翻看看,这样长期有效记忆会很深刻。

 多线程的书籍有很多,但是通俗易懂,结构层次清晰的我还是推荐一本书《java多线程编程核心技术》

好了,言归正传。我们来一起学习多线程吧。   

 

1、 进程和线程的概念

 什么是进程呢? 

进程就是一个程序运行中所占用一定的资源,进程是程序的实体。

什么又是线程呢?

线程就是进程里独立运行的子程序,比如音乐播放器边播放音乐,边去下载音乐。这就是2个子程序同时进行的。、

那用多线程有什么好处吗?

使用多线程,可以充分利用CPU资源。现在多核CPU很常见,一个程序的多个线程在不同时间在CPU不同核中进行处理,而不用等一个任务执行完后再执行下一个任务,这样效率太低了。但是多个线程在不同核中不停地切换,就需要消耗一定的时间资源。

 

 

2、如何使用多线程 

java使用多线程有两种方法:

1)继承Thread类

其实,Thread类也是实现了Runnabled的接口

public class Thread implements Runnable {}
public class ThreadDemo extends Thread{}

 

2)实现Runnabled接口

public class ThreadDemo implements Runnable {

      @Override
	public void run() {
		
	}

}

我们来看看下面的一段代码:

public class ThreadDemo extends Thread {
	private int i = 0;
	
	@Override
	 public void run() {
		i++;
		System.out.println("i:" + i);
	}

	public static void main(String[] args0) {
		ThreadDemo threadDemo = new ThreadDemo();
		Thread t = new Thread(threadDemo);
		Thread t2 = new Thread(threadDemo);
		Thread t3 = new Thread(threadDemo);
		Thread t4 = new Thread(threadDemo);
		Thread t5 = new Thread(threadDemo);
		t.start();
		t2.start();
		t3.start();
		t4.start();
		t5.start();
		//System.out.println("run over.");
	}
}

结果是:

可以看出线程是乱序执行的,如果想让它按照顺序执行,这样的程序是线程不安全的。也就是数据共享,没有原子性。其他线程容易篡改变量的值,造成了脏读、幻读的影响,将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用, 从而保证了该变量的唯一性和准确性就使用 synchronized关键字。

这个synchronized就把run()方法锁定了,每次只能进去一个线程,去修改它的值。其他线程在抢着这把锁的key,等到前面一个线程执行完run()方法内的程序后,下一个随机线程获取了key再去执行run()方法。

 

3、  currentThread()方法是获取当前线程

可以看出t.run()和t.start()当前线程不一致。这是因为t.start()方法是被Thread类的线程Thread-1调用的,而run方法是main方法里直接调用的,所以是main线程。

 

4、isAlive()

线程是否存活。

 

5、sleep()方法

让真正执行的线程休眠(暂停执行)。

@Override
	 public void run() {
		try {
			System.out.println("begin...");
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("run:"+this.isAlive());
	}

打印begin...两秒后,打印后面的run:true。

 

6、getId()方法

获取线程ID。

 

7、停止线程

停止线程很重要,一般来说有stop()强制停止线程。但因为太暴力,会让一个正在运行的线程突然终止,数据得不到同步处理,对象突然被解锁,后果很严重。

我们可以采用interrupt方法来终止线程。interrupt方法只是给这个线程标识为“要终止”的状态,而并不是调用就立即生效。

我们可以采用在run方法中判断是否是interrupt状态来抛出异常终止线程,或者return返回来终止线程。

public class ThreadDemo3 extends Thread {
	@Override
	/*public void run() {
		super.run();
		try {
			for (int i = 0; i < 10000; i++) {
				//如果线程状态为终止
				if (this.isInterrupted()) {
					System.out.println("我要停止了...");
					//抛出异常
					throw new InterruptedException();
				}
				System.out.println("i:" + i);
			}
			System.out.println("for循环外代码块..");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}*/
	public void run() {
		while (true) {
			for (int i = 0; i < 10000; i++) {
				if (this.isInterrupted()) {
					System.out.println("我要停止了...");
					// 返回结束线程
					return;
				}
				System.out.println("i:" + i);
			}
			System.out.println("for循环外代码块..");
		}
	}

	public static void main(String[] args0) {
		try {
			ThreadDemo3 threadDemo = new ThreadDemo3();
			threadDemo.start();
			Thread.sleep(100);
			threadDemo.interrupt();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}
}

两种方法终止线程 ,终止后for循环外的代码是不会执行的,直接结束了。

 

 

8、暂停线程

thread. suspend();暂停线程

thread.resume();恢复线程

缺点是容易造成公共的同步对象独占,使其他线程访问不到公共同步对象。也就是缺点:不同步。

 

9、yieId方法

放弃当前CPU的资源,让给其他任务占用CPU。但放弃的时间不确定,可能刚刚放弃,又被占用了。

Thread.yieId();

 

10、线程优先级

 线程的优先级越高,得到的CPU资源越多。一共分为1-10等级。如果超越这个范围就会报IllegalArgumentException()异常。

线程的优先级具有继承性,也就是说子线程继承父线程优先级。默认是5。

Thread.currentThread().getPriority();//获取线程优先级

Thread.currentThread().setPriority(10);//设置线程优先级

优先级高的线程并不一定先执行完,具有随机性。

 

11、守护线程

守护线程是陪伴另一个线程,当进程中不存在非守护线程时,守护线程会自动销毁。GC(垃圾回收器)就是一个守护线程。

 

猜你喜欢

转载自blog.csdn.net/lwq657359703/article/details/81142673
今日推荐