进程:线程离不开进程,先说一下什么是进程!(打开资源管理器,我们就能看到,当前运行的进程)。
线程:是进程中的单个顺序控制流,是一条执行路径。
单线程:一个进程如果只有一条执行路径,则成为单线程程序。
多线程:一个进程如果有多条执行路径,则成为多线程程序。
实现多线程
方式一:继承Thread类
1.定义一个类MyThread 继承Thread类
2.在MyThread类中重写Run()方法
3.创建对象
4.启动线程 用Start方法
public class MyThread extends Thread {
@Override
public void run() {
for (int i=0;i<100;i++){
System.out.println(i);
}
}
}
public class MyThreadDemo {
public static void main(String[] args) {
MyThread m1=new MyThread();
MyThread m2=new MyThread();
m1.start();
m2.start();
}
}
方法2:实现Runnable接口
定义一个MyRunnable类,实现Runnable接口
在MyRunnable类中重写run方法
创建MyRunnable类的对象
创建Thread类对象,将MyRunnable对象作为构造方法的参数
启动线程
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
public class MyRunnableDemo {
public static void main(String[] args) {
MyRunnable my=new MyRunnable();
Thread t1=new Thread(my);
Thread t2=new Thread(my);
t1.start();
t2.start();
}
}
问题: 为什么要重写run()方法?
run方法是用来封装被线程执行的代码。
run()方法和start()方法的区别?
run():封装线程执行的代码,直接调用,相当于普通方法的调用。
start():启动线程,然后由JVM调用此线程的run()方法。
设置和获取线程名称
public static void main(String[] args) {
MyThread m1=new MyThread();
m1.setName("王");
String name = m1.getName();
System.out.println(name);
}
线程调度
java中使用的是抢占式调度:优先级高的线程先使用CPU。优先级相同,会随机选一个。优先级高的线程获取的CPU时间片多一点。
MyThread m1 = new MyThread();
MyThread m2 = new MyThread();
MyThread m3 = new MyThread();
//获取线程的优先级,优先级默认是5,最高是10,最小是1.
// System.out.println(m1.getPriority());//5
// System.out.println(m2.getPriority());//5
// System.out.println(m3.getPriority());//5
//更改线程的优先级
m1.setPriority(1);
m2.setPriority(10);
m3.setPriority(1);
线程控制
//Thread.sleep(); 使当前正在执行的线程停留,指定的秒数,然后继续执行。
//vodi join();等待这个线程死亡。
//下面例子,m1,结束后,m2,m3才运行。
MyThread m1 = new MyThread();
MyThread m2 = new MyThread();
MyThread m3 = new MyThread();
m1.setName("王");
m2.setName("李");
m3.setName("孙");
m1.start();
try {
m1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
m2.start();
m3.start();
//void setDaemon(boolean on) 将此线程标记为守护线程,运行的线程都是守护线程时,java虚拟机将退出。
//例子:当主线程刘备结束后,关羽和张飞也退出线程。
MyThread m1 = new MyThread();
MyThread m2 = new MyThread();
m1.setName("关羽");
m2.setName("张飞");
Thread.currentThread().setName("刘备");
m1.setDaemon(true);
m2.setDaemon(true);
m1.start();
m2.start();
for (int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
线程生命周期
线程同步
案例:买票系统,3个窗体同时买票,然后用多线程。
public class SellTicket implements Runnable{
private int tickets=100;
@Override
public void run() {
while(true){
if (tickets>0){
try{
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"张票");
tickets--;
}
}
}
}
public class SellTickerDmo {
public static void main(String[] args) {
SellTicket st=new SellTicket();
Thread t1=new Thread(st,"窗体1");
Thread t2=new Thread(st,"窗体2");
Thread t3=new Thread(st,"窗体3");
t1.start();
t2.start();
t3.start();
}
}
上面这样写会出问题,就是一张票,卖了好多次。我们需要的是,把操作共享数据的多条语句锁起来,就是加锁,同一时间,只能一个去访问。
同步代码块方法解决问题:
public class SellTicket implements Runnable{
private int tickets=1000;
private Object obj=new Object();
@Override
public void run() {
while(true){
//加锁
synchronized (obj){
if (tickets>0){
try{
Thread.sleep(10);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"张票");
tickets--;
}
}
}
}
}
Lock锁,解决同步问题:
Lock是接口,不能直接实例化使用,可以使用它的实现类ReentrantLock。
主要方法,获得锁 施放锁。
public class SellTicket implements Runnable{
private int tickets=1000;
private Lock lock =new ReentrantLock();
@Override
public void run() {
while(true){
try{
lock.lock();
if (tickets>0){
try{
Thread.sleep(10);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"zhang票");
tickets--;
}
}finally {
lock.unlock();
}
}
}
}
线程安全的类:
如果需要执行同步,并且保证线程安全可以使用下面的类。它们的底层方法都是用 synchronized 加锁的。
StringBuffer sbf=new StringBuffer();
//下面这两个是线程安全的集合,但是我们一般不会去用。用下面的方法转!
Vector ve=new Vector();
Hashtable ht=new Hashtable();
//下面方法可以把集合转成 线程安全的。
List<String> list = Collections.synchronizedList(new ArrayList<String>());