多线程(一)
进程与线程:进程是一个正在执行的程序,每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或叫一个控制单元。线程就是进程中的一个独立的控制单元。一个进程中至少有一个线程。
Java虚拟机启动时就会有一个进程,该进程中至少一个线程负责java程序的执行。而且这个线程运行的代码存在于main方法中,并且该线程称之为主线程。
如何创建一个线程:
1、 继承方式:java中已经提供了对线程这类事物的描述就是Thread,可以通过继承Thread类创建一个新的线程。
classDemo extends Thread{
/*
覆盖run方法的原因:run方法是用来存储建立的线程所要执行的代码逻辑。
*/
@Override
public void run() {
super.run();
for (int i = 0; i < 400; i++) {
System.out.println("hi,陈从宾,我是Demo线程"+i);
}
}
}
publicclass ThreadDemo {
public static void main(String[] args) {
Demo demo = new Demo();
demo.start();
for (int i = 0; i < 400; i++) {
System.out.println("hi,我是main线程"+i);
}
//demo.start();
}
}
2、 实现方式:实现Runable接口已达到多线程:1)定义类实现Runable接口2)覆盖Runable接口中的run方法。3)通过Thread类建立线程对象。4)将Runable接口的子类对象作为实际参数传递给Thread类的构造函数。5)调用Thread类对象的start方法(该线程运行的代码是Runable接口中定义的run方法)
代码示例:
package com.abin;
class Ticket implements Runnable{
private int ticket = 100;
@Override
public void run() {
while (true) {
if (ticket>0) {
System.out.println(Thread.currentThread().getName()+"¡¤¡¤sale"+ticket--);
}
}
}
}
public class RunableDemo {
public static void main(String[] args) {
Ticketticket = new Ticket();
Threadth1 = new Thread(ticket);
Threadth2 = new Thread(ticket);
Threadth3 = new Thread(ticket);
Threadth4 = new Thread(ticket);
th1.start();
th2.start();
th3.start();
th4.start();
}
}
第一种(继承方式)与第二种(实现方式)实现多线程之间的区别:1)继承方式将线程执行的代码放在Thread子类的run方法中,实现方式将代码放在接口子类的run方法中。2)实现方式避免了单继承的局限性。
线程安全问题。出现多线程安全问题的原因是:当多条语句在操作同一个线程间共享的数据时,一个线程的多条语句(run方法包含的内容)只执行了一部分,就被另一个线程打断,进而导致共享数据的错误。解决的办法是:对正在执行的线程进行控制,使其在占用线程间共享资源时,不被其他线程打断,以保证该线程的顺利完成。Java的解决办法是:使用同步代码块synchronized(对象){};其中的对象时“锁”。同步代码块只需要应用在可能是多个进程间的共同资源上。线程同步的前提:1)必须有两个或两个以上的线程,产生共用资源的使用冲突。2)多个同步线程要有同一把锁,以保证多个线程只有一个线程进行。多线程的弊端是:由于每个线程在执行之前均需要判断其他同步线程对锁的使用情况,这在一定程度上造成了资源的消耗。
同步函数:只需要在定义函数时在函数返回值类型前加上关键字synchronized即可,如:public synchronized voidfunction (){};同步函数默认的锁为this。如果同步函数被静态(static)修饰后使用的锁是:类名.class,原因是:静态进内存时内存中没有本类对象,但是一定有该类对应的字节码文件对象,且该对象是唯一的。
在使用线程同步过程中需要明确以下三个问题:1)明确哪些代码是多线程代码。2)明确哪些是共享数据。3)明确多线程运行代码中哪些语句是操作共享数据。