多线程——讲的不错,认认真真做的笔记,认真再看!
Posted AntarcticPenguin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程——讲的不错,认认真真做的笔记,认真再看!相关的知识,希望对你有一定的参考价值。
一、线程和进程
进程可以看成是一个运行中的程序,每个应用就是一个运行的程序,可以看成是一个进程。操作系统会为每个进程分配内存空间和CPU时间等。多任务支持了多进程。
线程成为轻量级的进程,有自己的运行环境。线程存在于进程中,每个进程最少有一个线程,线程分享进程的资源。例如程序中同时进行数据读取和数据处理,这样能够提高效率,这时候就需要两个线程。
二、java中的多线程实现的方式
java中提供了两种实现线程的方式:
- 通过继承Thread类实现多线程
1、继承Thread类实现线程类,需要覆盖run方法
public class MyThread extends Thread{
public void run(){
//定义线程要执行的代码
}
}
2、通过线程类创建线程对象:
Thread t=new MyThread();
Thread t=new MyThread("线程的名字");
3、线程的启动通过start方法实现
看下面这个例子1:
public class ThreadTest {
public static void main(String[] args) {
System.out.println("主线程开始运行...");
PrintNumber pn = new PrintNumber();
pn.start();//这个就要看系统CPU是否给它执行时间,给就执行不给,不能执行
PrintLetter pl = new PrintLetter();
pl.start();
System.out.println("主线程运行结束...");
}
}
class PrintNumber extends Thread{//实现线程就要几成Thread类,实现方法
public void run(){
for(int i=1;i<1000000;i++){//循环100万次,每一万次输出一个
if(i%10000==0)
System.out.println("----"+i);
}
}
}
class PrintLetter extends Thread{
public void run(){
for(int i=0;i<1000000;i++){
if(i%10000==0)
System.out.println((char)(\'a\'+i%26));
}
}
}
-
这个结果就是,main主线程开始,然后进行其他的线程,主线程结束,由于系统分配着进行时间,所以两个线程穿插交替进行,可以运行一下体验一下,如图下面:
- 通过实现Runable接口实现多线程
1、需要实现run方法
public class MyThread2 implements Runable{
public void run(){
//定义线程要执行的代码
}
}
2、创建线程对象:
Thread tt=new MyThread(new MyThread2());
3、线程的启动通过start方法实现
看下面的例子2。
public class RunnableTest {
public static void main(String[] args) {
System.out.println("主线程开始运行...");
PrintNumber pn = new PrintNumber();
Thread t1 = new Thread(pn);
Thread t3 = new Thread(pn);
t1.start();
t3.start();
PrintLetter pl = new PrintLetter();
Thread t2 = new Thread(pl);
t2.start();
System.out.println("主线程运行结束...");
}
}
class PrintNumber implements Runnable{
public void run(){
for(int i=1;i<1000000;i++){
if(i%10000==0)
System.out.println("----"+i);
}
}
}
class PrintLetter implements Runnable{
public void run(){
for(int i=0;i<1000000;i++){
if(i%10000==0)
System.out.println((char)(\'a\'+i%26));
}
}
}
经过实践可以,跟上面那个结果类似
三、线程的名字
- 通过继承Thread类实现多线程
class MyThread extends Thread{
public MyThread(String name){
super(name);
}
......
}
- 通过实现Runable接口实现多线程
MyRunnable r=new MyRunnable();
Thread t3=new Thread(r,"线程3");
- 通过Thread对象的setName方法设置
- 调用getName方法得到线程的名字
- 例子6.3线程名字的使用
public class ThreadNameTest {
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
Thread t1 = new MyThread("线程1");
Thread t2 = new MyThread();
t2.setName("线程2");
Thread t3 = new Thread(r, "线程3");
Thread t4 = new Thread(r);
t4.setName("线程4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class MyRunnable implements Runnable {
public void run() {
for (int i = 1; i < 11; i++)
System.out.println(Thread.currentThread().getName() + "--" + i);
}
}
class MyThread extends Thread {
public MyThread() {
}
public MyThread(String name) {
super(name);
}
public void run() {
for (int i = 1; i < 11; i++)
System.out.println(getName() + "--" + i);
}
}
四、线程的优先级
- 默认情况下,一个程序的多个线程具有相同的优先级,也就是获得CPU的概率相同。可以通过设置线程的优先级来调整每个线程获得CPU的机会大小。
- 调用线程的setPriority方法设置优先级,参数表示优先级。优先级的最小值是1,最大的值是9,默认值是5。
- 需要设置优先级的情况比较少。
- 例子(6.4)线程的优先级
public class ThreadPriority implements Runnable{
public static void main(String[] args) {
Runnable r1 = new ThreadPriority();
Runnable r2 = new ThreadPriority();
Thread thread1 = new Thread(r1,"t1");
thread1.setPriority(1);
Thread thread2 = new Thread(r2,"t2");
thread2.setPriority(7);
thread1.start();
thread2.start();
}
public void run(){
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
五、让线程等待
根据需要可以让线程等待一段时间再执行,可以通过4种方式:
- 使用sleep让线程等待一段时间
- 使用yield方法让线程让出执行机会
- 使用join让线程等待
- wait方法与notity一起使用,在后面单独介绍,这里介绍3个
(1)使用sleep方法让线程等待
- 调用Tread的sleep方法让当前线程等待一段时间,参数指出等待时间,单位为毫秒。sleep方法需要使用try....catch处理异常
例子6.5让线程休息
public class ThreadSleep implements Runnable {
public void run() {
for (int k = 0; k < 5; k++) {
if (k == 2) {
try {
Thread.sleep(5000);//让它等待了5秒钟,运行结果就是0 1然后等待5秒再出现2 3 4
} catch (Exception e) {
}
}
System.out.print(" " + k);
}
}
public static void main(String[] args) {
Runnable r = new ThreadSleep();
Thread t = new Thread(r);
t.start();
}
}
(2)使用yield方法让出执行权
- yield方法与sleep方法相似,只是它不能由用户指定线程暂停多长时间。sleep方法可以使低优先级的线程得到执行机会,当然也可以让同优先级和高优先级的线程有执行的机会。而yield方法只能使同优先级的线程有执行的机会。
例子6.7使用yield方法让出执行权
public class ThreadYield {
public static void main(String[] args) {
Thread t1 = new MyThread();
t1.setName("线程A");
Thread t2 = new MyThread2();
t2.setName("线程B");
t1.start();
t2.start();
}
}
class MyThread extends Thread{
public void run(){
for(int i=0;i<100;i++){
Thread.yield();
Thread.yield();
System.out.println(Thread.currentThread().getName()+i);
}
}
}
class MyThread2 extends Thread{
public void run(){
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+i);
}
}
}
(3)使用join方法让某个线程先执行完
- 可以使用join方法让某个线程执行完之后再执行另外一个线程
例子6.8(没有使用join)——输出结果0
public class ThreadJoin extends Thread{
public static int a = 0;
public void run() {
for (int k = 0; k < 5; k++) {
a = a + 1;
}
}
public static void main(String[] args) {
Runnable r = new ThreadJoin();
Thread t = new Thread(r);
t.start();
System.out.println(a);
}
}
例子6.9(使用join)——输出结果5
public class ThreadJoin extends Thread{
public static int a = 0;
public void run() {
for (int k = 0; k < 5; k++) {
a = a + 1;
}
}
public static void main(String[] args) {
Runnable r = new ThreadJoin();
Thread t = new Thread(r);
t.start();
try {
t.join();
} catch (InterruptedException e) {
}
System.out.println(a);
}
}
六、实例:实现人能够同时说话和开车
- 编写People类表示人,People类具有说话(speak)和开车(Drive)的功能,让Person类支持多线程,即能够在开车的同时说话
public class Person implements Runnable {
int speakNo = 0;
int driveNo = 0;
private boolean canStop = false; // 是否停止线程
public static void main(String[] args) {
Person person = new Person();
Thread t1 = new Thread(person, "speak"); // 第二个参数给出线程的名字
Thread t2 = new Thread(person, "drive");
t1.start();
t2.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
person.setCanStop(true);
}
public void run() {
while (true) {
String name = Thread.currentThread().getName();
if (name.equals("speak")) {
speak();
} else {
drive();
}
if (canStop) {
break;
}
}
}
public void drive() {
out.println("正在--------------开车!" + driveNo++);
try {
Thread.sleep(5);
} catch (InterruptedException e) {
}
}
public void speak() {
out.println("正在说话!" + speakNo++);
try {
Thread.sleep(5);
} catch (InterruptedException e) {
}
}
public boolean isCanStop() {
return canStop;
}
public void setCanStop(boolean canStop) {
this.canStop = canStop;
}
}
七、资源同步
多线程的问题
...
int tickets = getTicket(); (1)
setTickets(tickets-1); (2)
...
假设A线程和B线程分别表示两个售票窗口,可能的执行过程如下:
A线程执行(1),B线程执行(1),A线程执行(2),B线程执行(2),
资源同步可以使用关键词synchronized,相当于对资源加锁,加锁之后其他代码就不能访问了,只有等当前代码执行完之后并解锁,其他的代码才能访问。synchronized可以用在对象上,也可以用在方法上,也可以用在一段代码上。
例子:
6.11在对象上加锁
public class SynchronizeDemo {
public static void main(String[] args) {
TicketManager tm = new TicketManager();
Thread t1 = new Seller(tm, "A窗口");
Thread t2 = new Seller(tm, "B窗口");
t1.start();
t2.start();
}
}
class Seller extends Thread {
TicketManager tm;
public Seller(TicketManager tm, String name) {
super(name);
this.tm = tm;
}
public void run() {
while (true) {
synchronized (tm) {
int temp = tm.getCount();
if (temp == 0)
break;
temp--;
System.out.println(Thread.currentThread().getName()
+ "卖了一张票!还剩下" + temp + "张票!");
tm.setCount(temp);
try {
sleep(100);
} catch (InterruptedException e) {
}
}
}
}
}
class TicketManager {
int count = 100;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
6.12在方法上加锁
public class SynchronizeDemo {
public static void main(String[] args) {
Manager manager = new Manager();
Thread t[] = new Thread[10];
for(int i=0;i<5;i++){
t[i] = new Person(manager,"第"+(i+1)+"个人");
t[i].start();
}
}
}
class Person extends Thread {
Manager manager;
public Person(Manager manager, String name) {
super(name);
this.manager = manager;
}
public void run() {
for(int i=0;i<10;i++) {
manager.eat();
try {
sleep(100);
} catch (InterruptedException e) {
}
}
}
}
class Manager {
public synchronized void eat(){
String threadName = Thread.currentThread().getName();
System.out.println(threadName+":用刀");
System.out.println(threadName+":----用叉");
}
}
八、wait和notify
某个线程在执行的过程中发现需要的资源不可用的时候,就需要等待,调用资源的wait方法,让当前线程处于等待状态。
处于等待状态的线程自己不能继续执行,必须等待其它线程唤醒它,其他线程通过notify或者notifyAll方法来唤醒。
例子:生成者的产品要放到仓库中,消费者需要从仓库中消费商品,而仓库中只能存放10件商品。
Producer.java
public class Producer extends Thread{
private Store store;
private boolean canStop = false;
public void setCanStop(boolean canStop) {
this.canStop = canStop;
}
public Producer(Store store,String name){
super(name);
this.store = store;
}
public void run() {
while(true){
if(canStop)
break;
synchronized(store){
// 等待仓库有空位置
while(store.getQuantity() == 10){
try{
store.wait();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
// 生产产品
String threadName = Thread.currentThread().getName();
out.println(threadName + "生产了一个商品!");
store.put();
// 唤起其他等待者
store.notifyAll();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Consumer.java
public class Consumer extends Thread{
private Store store;
private boolean canStop = false;
public void setCanStop(boolean canStop) {
this.canStop = canStop;
}
public Consumer(Store store,String name){
super(name);
this.store = store;
}
public void run() {
while(true){
if(canStop)
break;
synchronized(store){
// 得到仓库有空位置
while(store.getQuantity() == 0){
try{
store.wait();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
// 消费
String threadName = Thread.currentThread().getName();
out.println(threadName + "消费了一个商品!");
store.get();
store.notifyAll();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Store.java
public class Store {
/*
* 表示库存,quantity的值会影响生产者和消费者,
* 有产品才可以消费,仓库没有满才可以生产
* 初始为0,最大为10
*/
private int quantity = 0;
public int getQuantity() {
return quantity;
}
public void put() {
quantity++;
}
public void get(){
quantity--;
}
}
Main.java
public class Main {
public static void main(String[] args) {
Store store = new Store();
Producer t1 = new Producer(store, "producer1");
Producer t2 = new Producer(store, "producer2");
Consumer t3 = new Consumer(store, "consumer1");
Consumer t4 = new Consumer(store, "consumer2");
t1.start();
t2.start();
t3.start();
t4.start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t1.setCanStop(true);
t2.setCanStop(true);
t3.setCanStop(true);
t4.setCanStop(true);
}
}
以上是关于多线程——讲的不错,认认真真做的笔记,认真再看!的主要内容,如果未能解决你的问题,请参考以下文章