关于多线程的,相关的资料网上多的是,下面是我在实际工作中有人问到的最多的问题,现在就写写,和大家一起交流交流哦
要谈线程首先要知道什么是进程,什么线程?关于书面的解释很多,大家可以网上一搜大把的是在此我就不提了。举个例子吧:
应用程序是进程,那么这个程序在运行过程中做的事情就是线程。
工作: 听写单词 //相当于一个程序
事件1: 老师念 //相当于这个程序中要完成的一项工作
事件2: 学生写 //相当于这个程序中要完成的一项工作
实现多线程有两种方法:一是继承Thread类 ,一是实现Runnable接口
继承Thread 类实例:
import java.util.*;
public class TimePrinter extends Thread {
int pauseTime;
String name;
public TimePrinter(int x, String n) {
pauseTime = x;
name = n;
}
public void run() { //重写了run()方法
while(true) {
try {
System.out.println(name + ":" + new
Date(System.currentTimeMillis()));
Thread.sleep(pauseTime);
} catch(Exception e) {
System.out.println(e);
}
}
}
static public void main(String args[]) {
TimePrinter tp1 = new TimePrinter(1000, "间隔1秒");
tp1.start(); //进程由start()函数调用
TimePrinter tp2 = new TimePrinter(3000, "间隔3秒");
tp2.start();
}
}
实现runnable 接口实例:
import java.util.*;
public class TimePrinter2
implements Runnable {
int pauseTime;
String name;
public TimePrinter2(int x, String n) {
pauseTime = x;
name = n;
}
public void run() {
while(true) {
try {
System.out.println(name + ":" + new
Date(System.currentTimeMillis()));
Thread.sleep(pauseTime);
} catch(Exception e) {
System.out.println(e);
}
}
}
static public void main(String args[]) {
Thread t1 = new Thread (new TimePrinter(1000, "间隔1秒"));
t1.start(); //进程由start()函数调用
Thread t2 = new Thread (new TimePrinter(3000, "间隔3秒"));
t2.start();
}
}
此接口只有一个函数,run(),此函数必须由实现了此接口的类实现。
注意,当使用 runnable 接口时,您不能直接创建所需类的对象并运行它;必须从 Thread 类的一个实例内部运行它。许多程序员更喜欢 runnable 接口,因为从 Thread 类继承会强加类层次。
synchronized 同步
出现多个线程访问同一个对象时就会用到synchronized
大多数有用的程序中,线程之间通常有信息流。试考虑一个金融应用程序,它有一个 Account 对象,如下例中所示:
public class Account {
String holderName;
float amount;
public Account(String name, float amt) {
holderName = name;
amount = amt;
}
public void deposit(float amt) {
amount += amt;
}
public void withdraw(float amt) {
amount -= amt;
}
public float checkBalance() {
return amount;
}
}
在此代码样例中潜伏着一个错误。如果此类用于单线程应用程序,不会有任何问题。但是,在多线程应用程序的情况中,不同的线程就有可能同时访问同一个 Account 对象,比如说一个联合帐户的所有者在不同的 ATM 上同时进行访问。在这种情况下,存入和支出就可能以这样的方式发生:一个事务被另一个事务覆盖。这种情况将是灾难性的。但是,Java 编程语言提供了一种简单的机制来防止发生这种覆盖。每个对象在运行时都有一个关联的锁。这个锁可通过为方法添加关键字 synchronized 来获得。这样,修订过的 Account 对象(如下所示)将不会遭受像数据损坏这样的错误:
public class Account {
String holderName;
float amount;
public Account(String name, float amt) {
holderName = name;
amount = amt;
}
public
synchronized void deposit(float amt) {
amount += amt;
}
public
synchronized void withdraw(float amt) {
amount -= amt;
}
public float checkBalance() {
return amount;
}
}
deposit() 和 withdraw() 函数都需要这个锁来进行操作,所以当一个函数运行时,另一个函数就被阻塞。请注意, checkBalance() 未作更改,它严格是一个读函数。因为 checkBalance() 未作同步处理,所以任何其他方法都不会阻塞它,它也不会阻塞任何其他方法,不管那些方法是否进行了同步处理。
待续,有时间再来补充哦