`

线程总结

    博客分类:
  • Java
 
阅读更多

一、程序,进程,线程的区别

       程序是一段静态的代码,是软件执行的蓝本。

       进程可以理解为正在进行的程序,它是从程序加载、执行、执行完毕的整个过程,多个进程可以共享操作系统所管理的资源,比如剪切板。每个进程都单独占用一块内存,多个进程之间不能数据共享,必须通过网络交换数据。

       线程是比进程更小的执行单位,一个进程在执行过程中,可以产生多个线程。线程是一个进程内部的多个并行的运行单元,同一个进程的多个线程之间可以通过内存共享数据。通俗地讲,线程是运行在进程中的小“进程”。

 

二、Java中的多线程

       Java程序执行时,先启动了一个主线程,即main方法。在main方法中,可以开启其他线程。当main方法执行完毕的时候,程序不会退出,只有所有线程都执行完毕,Java程序才会退出。

       线程的使用方法:

       1.继承Thread类

       

public class A extends Thread{
	public void run(){
		//线程要干的活...
	}
}

class Main{
         public static void main(String args[]){
                    new A().start();//这样就执行了A中的run方法,当run执行完毕,线程结束

          }

}

 

 

       2.实现Runnable接口

 

 

/**
 *刷新Jpanel的线程
 *
 **/

public class UpdataCenter implements Runnable {

	JPanel center;

	public UpdataCenter(JPanel center) {
		this.center = center;
	}

	@Override
	public void run() {
		while (true) {
			if (!MainUI.pause) {
				center.repaint();
			}
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

//调用
UpdataCenter st = new UpdataCenter(center);
		Thread th = new Thread(st);
		th.start();//开启线程

 

 

         当有多个线程执行的时候,由于CPU每次只处理一个,他们的处理顺序是不确定的,所以先开启的线程不一定先执行。

 

        当run方法执行完毕,线程变成死亡状态,释放了分配给线程对象的内存。如果在run未执行完重复调用start()会抛出IlIegalThreadStateException。

 

三、线程中的方法

       sleep(long a);休眠a毫秒,再往下执行。

       interrupt()可以吵醒休眠的线程,结束休眠。

       isAlive();线程在执行run的过程中返回true,开始执行前和执行结束后返回false。

 

四、线程同步

        同步:有多个线程同时操作一个变量,这个时候就没办法确定程序的正确性了,所以应该想办法解决这种 同时执行的时候对变量改变的不确定性,所以得先执行玩这个再执行其它,同时只做一件事。

        异步:多线程可以同时操作,不会发生结果错误。、

 

        比如在两个地方同时使用网银转账。本来银行卡剩余1000,在A处转出800,在B处转出500.最后本来卡内余额应该为-300。但是由于使用两个线程在同时取钱,这就造成了结果的不确定性。

 

线程A处从内存中读到money = 1000;对其进行-800的操作,money = 200;

线程B处从内存中读到money = 1000;对其进行-500的操作,money = 500;

两个线程计算完毕,将数据放回原地,而Cpu只能一次一次的放(同时只能处理一件事,只是速度非常快)CPU有可能先将200放回去,再将500放回去,那么卡内余额变成了500(200被覆盖),反之亦然。

 

       当然,还有一种情况是,线程A处从内存中读到money = 1000;对其进行-800的操作,money = 200,将其放回原地;在进行B的操作(线程执行顺序具有不确定性)。这个时候卡内余额变成了-300。

 

       如何避免第一种情况的发生?这就是线程同步需要处理的问题。

 

       Java中提供了关键字synchronized(同步),使用该关键字可以修饰方法,对象。

使用它修饰之后,当一个线程取出了这个对象对其修改或者这个方法对其执行。其余线程必须等待它先执行完毕。这样就避免了第一种错误。

 

       使用方法:

 

public class Main {
	public static void main(String[] args) {
		Account ac = new Account();
		new Card(ac, 800).start();
		new Card(ac, 400).start();
		
	}
}

package Thread20140715;

public class Card extends Thread {

	Account ac;
	int n;

	public Card(Account ac, int n) {
		this.ac = ac;
		this.n = n;
	}

	/**
	 * 异步:可以同时修改这块内存,导致结果出错。
	 * 
	 * 如果没在Account锁定,
	 * 
	 * 输出结果:-200 -200或者200 200或者600 600
	 * 
	 * 否则,结果为 200/600 -200
	 */
	public void run() {
		ac.getMoney(n);
		ac.getMoney1(n);
		ac.getMoney2(n);
	}

	/**
	 * 同步:只允许一个Account操作修改这块内存。
	 * 
	 * 输出结果: 200/600 -200
	 */
	// public void run() {
	// synchronized (ac) {// 锁定ac
	// ac.getMoney(n);
	// }
	// }

}

package Thread20140715;

public class Account {

	int money = 1000, money1 = 1000, money2 = 1000;

	/**
	 * 异步
	 * 
	 * @param n
	 *            要取多少钱
	 */
	public void getMoney1(int n) {
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		money1 -= n;
		System.out.println("剩余金额1:" + money1);
	}

	/**
	 * 同步
	 * 
	 * @param n
	 *            要取多少钱
	 */
	public void getMoney2(int n) {
		synchronized (this) {// 锁定this对象,所有属性不可修改
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			money2 -= n;
			System.out.println("剩余金额2:" + money2);
		}
	}

	/**
	 * 同步
	 * 
	 * @param n
	 *            要取多少钱
	 */
	public synchronized void getMoney(int n) {
		// 锁定方法,此时不锁定属性,
		// 所以其它方法仍然可对money进行修改,导致结果出错

		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		money -= n;
		System.out.println("剩余金额:" + money);

	}
}

输出结果:
剩余金额:200
剩余金额1:600
剩余金额:-200
剩余金额2:200
剩余金额1:600
剩余金额2:-200

由结果可知,剩余金额1是错误的结果,因为1没有使用同步(这个结果很随机,但是只有1可能错误)。

 

五、锁

用来锁定中间的代码。

        Lock lc = new ReentrantLock();

lc.lock();

        ……

lc.unlock();

 

六、计时器线程

       使用方法:创建Timer计时器对象,创建相应任务。调用schedule方法。传入任务,第一次执行延长的时间,以后执行的周期。

       Timer timer = new Timer();

       EnermyPlaneCreator task = new EnermyPlaneCreator();

       timer.schedule(task, 800, 20000);

 

       public class EnermyPlaneCreator extends TimerTask{

              public void run() {}

       }

 

七、线程使用模型

1.监听器模型

在A线程中增加标记flag,在B线程中对A中的flag进行操作。B为A的监听线程。

例如:flag初始值为0,表示A没开始执行。当A start之后,将flag赋值为1,这时B就可以知道此时A已经开始执行了。当A执行到某个操作,flag=2,这是B也可以知道A执行到哪里了。

 

2.生产消费模型

开启一个生产者线程A,一个消费者线程B。

在A中生成对象,在B中消费对象。(例如ArrayList的add,remove操作)

由于线程的执行顺序不确定,这个时候A可能还没有生成,B就去消费了。程序就会有问题。

可以进行判断,当消费的时候判断是否已经有了生成,如果没有生产,就通知生产者进行生产并等待生产者进行生产。

 

示例代码:

public class Main {

	// 存放产品对象的队列
	static ArrayList<Computer> coms = new ArrayList<Computer>();

	public static void main(String[] args) {

		// 生产者
		Produce p = new Produce();
		p.start();

		// 消费者
		Customer c = new Customer();
		c.start();
	}
}


public class Computer {

	String name;

	public Computer(String name) {
		this.name = name;
	}

	@Override
	public String toString() {//打印对象时调用
		return name;
	}

}

public class Produce extends Thread {

	int i = 0;

	public void run() {
		while (true) {
			try {
				synchronized (Main.coms) {
					if (Main.coms.size() > 0) {
						Main.coms.wait();
					} else {
						Computer com = new Computer("第" + i + "台电脑");
						Main.coms.add(com);
						System.out.println("生产了电脑:" + com);
						i++;
						Main.coms.notify();
					}
				}
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}

	}

}

public class Customer extends Thread {

	public void run() {
		while (true) {
			try {
				synchronized (Main.coms) {
					// 如果产品不够,就等待
					if (Main.coms.size() <= 0) {
						Main.coms.wait();
					} else {
						Computer c = Main.coms.remove(0);
						System.out.println("-->消费了一台:" + c);
						Main.coms.notify();
					}
				}
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

 

 

 

 

 

 

 

 

0
0
分享到:
评论

相关推荐

    C#.net同步异步SOCKET通讯和多线程总结2[参照].pdf

    C#.net 同步异步 SOCKET 通讯和多线程总结 本文旨在总结 C#.net 中的同步异步 SOCKET 通讯和多线程编程,涵盖服务端和客户端的实现细节。 一、服务端实现 服务端使用 System.Net 和 System.Net.Sockets 命名空间...

    windows多线程总结

    【Windows多线程总结】 Windows操作系统提供了一套完整的API来支持多线程编程,使得开发者可以在同一进程中同时执行多个线程,实现并发处理任务。本文将深入探讨Windows多线程编程的基本概念、线程同步、线程池以及...

    JAVA多线程总结

    【JAVA多线程总结】 Java 多线程是Java编程中的关键特性,它允许程序同时执行多个任务,提高系统的效率和响应性。本篇总结涵盖了Java多线程的基础概念、创建与启动、线程调度、同步与协作以及新特性。 **一、Java...

    C#.net同步异步SOCKET通讯和多线程总结

    C#.net同步异步SOCKET通讯和多线程总结 C#.net同步异步SOCKET通讯和多线程总结是指在C#.net环境下实现的同步异步套接字通信和多线程编程的总结。套接字(Socket)是tcp/ip网络协议接口,内部定义了许多的函数和例程...

    java多线程总结(一)

    ### 总结 Java多线程提供了强大的并发处理能力,开发者可以通过继承`Thread`类或实现`Runnable`接口来创建和管理线程。正确使用`start()`方法而非`run()`方法是确保线程正确启动的关键。理解Java多线程的工作原理和...

    Java线程总结教程

    ### Java线程总结教程知识点详解 #### 一、操作系统与多线程概念 - **多任务与分时操作系统**:现代操作系统(如Windows、Linux)能够实现多任务处理,即在用户看来似乎多个应用程序在“同时”运行。实际上,这是...

    C++多线程总结[归纳].pdf

    C++多线程总结 本文档对C++多线程编程进行了总结,介绍了三种创建线程的方法:CreateThread函数、AfxBeginThread函数和_beginthread()/_beginthreadex()函数,同时对线程的管理和终止进行了详细的讲解。 ...

    Java编程中多线程总结

    ### Java编程中多线程总结 #### 一、Java多线程概述 Java多线程是Java编程语言中一个至关重要的部分,它允许程序在单个应用程序中并发地执行多个任务,极大地提高了程序的效率和响应性。在Java 5之前,多线程的...

    Java线程总结.pdf

    总的来说,Java线程总结的知识点涵盖了线程的基本概念、创建与管理、生命周期、同步机制、线程间通信以及线程的活跃性问题。理解和掌握这些知识点对于开发高效、稳定、并发的Java应用程序至关重要。

    线程总结笔记

    ### 线程总结笔记——基于Linux环境下的线程控制与同步 #### 一、引言 本篇“线程总结笔记”主要针对Linux环境下多线程编程中的关键概念进行了整理与归纳,尤其是针对线程同步的问题进行了深入探讨。通过一个具体...

    c#多线程总结文档.ppt

    c# 多线程总结

    MFC 多线程总结

    在Windows应用程序开发中,MFC(Microsoft Foundation Classes)框架提供了对多线程的支持,使得开发者可以构建更加复杂的并发系统。MFC中的线程分为两类:工作者线程和用户界面线程,它们各自有不同的特性和用途。 ...

    Java并发编程实践(java concurrency in practice)pdf (java多线程总结.ppt)

    配合`JAVA多线程总结.ppt`,你可以得到一个更直观和简洁的概览,快速回顾和掌握上述关键知识点。虽然中文版翻译可能存在不足,但原版英文书籍通常能更准确地传达作者的意图和细节,值得深入阅读。

    C#dotnet同步异步SOCKET通讯和多线程总结

    C#dotnet同步异步SOCKET通讯和多线程总结

    java多线程总结

    本文将深入探讨Java多线程的相关知识点,包括线程的创建、线程的状态、同步机制以及线程安全问题。 1. **线程的创建** Java提供了两种创建线程的方式: - **继承Thread类**:自定义类继承Thread类,并重写run()...

    我总结的Java线程总结

    Java线程是并发编程的核心部分,它允许程序在同一时间执行多个任务,极大地提高了程序的效率和响应速度。在Java中,实现多线程有两种主要方式:继承`Thread`类和实现`Runnable`接口。 1. 继承`Thread`类: 当创建...

    JAVA线程总结,包含线程池,显示使用线程实现异步编程,基于JDK中的Future实现异步编程,JDK中的FutureTask等

    JAVA线程总结,包含线程池,显示使用线程实现异步编程,基于JDK中的Future实现异步编程,JDK中的FutureTask等

    C++多线程总结

    本文将对C++中三种常见的线程创建方法进行总结,并讨论线程同步的相关知识。 1. 使用 `CreateThread` 函数生成的线程 - **函数原型**:`HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD ...

    MFC多线程总结.doc

    MFC(Microsoft Foundation Classes)是微软提供的一套C++库,用于简化Windows应用程序开发,它提供了对Windows API的封装,包括多线程支持。在MFC中,多线程分为两类:工作者线程(Worker Thread)和用户界面线程...

Global site tag (gtag.js) - Google Analytics