线程、同步

第一章:创建线程的方式之一、继承Thread类及常用方法
自定义线程类,继承自Thread,并重写run()方法:
public class Mythread extends Thread {
public Mythread(String name){
super(name);
}
@Override
public void run() {
for (int i = 0; i <20 ; i++) {
System.out.println(getName()+i);

    }
}

} 测试类:
public class Demo {
public static void main(String[] args) {
System.out.println(“这里是main线程”);
Mythread mt = new Mythread(“小黑”);
mt.start();
for (int i= 0; i<20 ; i++) {
System.out.println(“旺财”+i);

    }

}

}
注意:
1).重写的是run(),但启动线程是:start();
2).对于“一个线程对象”,只能调用一次start();
3).对于“一个线程类”,可以创建多个线程对象,每个线程对象都可以以独立的
线程运行。
Thread类的构造方法:
1).Thread():
2).Thread(String name):使用一个“线程名称”创建一个线程对象;
3).Thread(Runnable r):使用一个Runnable对象创建一个线程对象;
4).Thread(Runnable r,String n):使用一个Runnable和线程名称构造一个线程对象。
Thread的常用方法:
1).public String getName():获取线程名称。
注意:任何一个线程对象都有一个默认名称:Thread-[索引]
2).public void setName(String name):设置线程名。
3).public static Thread currentThread():获取当前的线程对象;
4).public static void sleep(long m):让当前的线程对象休息m毫秒
public static void main(String[] args) throws InterruptedException {
for (int i = 9; i >0 ; i–) {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd:mm:ss”);
String str = sdf.format(date);
System.out.println(str);
Thread.sleep(1000);

    }
    System.out.println("铛铛铛。。。。。。。。。。。。");
}

}

线程的创建方式二 实现Runnable接口及特点:
自定义类实现Runnable接口,并重写run方法:
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
System.out.println(“i=”+i);

    }
}

}
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread th1 = new Thread(myRunnable);
Thread th2 = new Thread(myRunnable);
Thread th3 = new Thread(myRunnable);
th1.start();
th2.start();
th3.start();
for (int k = 0; k <100 ; k++) {
System.out.println(“k =”+k);

    }

}

}

注意事项:
1).自定义类实现了Runnable接口,并没有继承自Thread,所以不是一个“线程”。
2).这种方式仍然需要Thread。
3).可以将一个自定义类的对象,传给多个Thread。
线程:这俩种方式的区别:
第一种方式需要子类继承自Thread 由于java是单继承,所以对子类造成了不方便
第二中方式需要子类实现Runnable接口,java允许一个类同时实现多个接口,所以对子类就比较方便。
线程, 匿名内部类的方式实现线程:
Thread的匿名子类:
public static void main(String[] args) {
new Thread(){
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
System.out.println(“i=”+i);
}
}
}.start();
Runnable的匿名子类:
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
System.out.println(“i=”+i);
}
}
}).start();
//打印主线程
for (int k = 0; k <100 ; k++) {
System.out.println(“k=”+k);
}
}
}
第二章:线程安全 多线程的安全性问题:
如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,
代码:
public class Ticket implements Runnable {
private int ticket = 100;

@Override
public void run() {
    while (true){
        if (ticket>0){
        try {
            Thread.sleep(100);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        String name = Thread.currentThread().getName();
             System.out.println(name+"正在卖"+ticket--);
        }
    }
}

}

public static void main(String[] args) {
Ticket t = new Ticket();
Thread t1 = new Thread(t,”窗口1”);
Thread t2 = new Thread(t,”窗口2”);
Thread t3 = new Thread(t,”窗口3”);
t1.start();
t2.start();
t3.start();
}
}
线程同步:
当我们使用多个线程访问同一个资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全性的问题,要解决这些问题 JAVA提供了同步机制(synchronized)来解决
根据上述代码分析的话:
窗口1线程进入操作的时候,窗口2和窗口3线程只能在外等着,窗口1操作结束,窗口1和窗口2和窗口3才有机会进入代码去执行,也就是说在某个线程修改共享资源的时候,其他线程不能修改该资源,等待修改完毕同步之后,才能去抢夺CPU资源,完成对应的操作,保证了数据的同步性,解决了线程不安全的现象。
有三种方式完成同步操作:
1.同步代码块。
2.同步方法。
3.锁机制。
同步代码块:
Synchronized关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问
格式:
Synchronized(同步锁){
需要同步的代码
}
我们来介绍一下什么是同步锁?
对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁。
1.锁对象 可以是任意类型
2.多个线程对象 要使用同一把锁
注意:在任何时候,最多允许一个线程拥有同步锁,谁拿到锁就进入代码块,其他的线程只能在外等着
代码:
public class Ticket implements Runnable{
private int ticket = 100;
Object lock = new Object();
//执行卖票操作
@Override
public void run() {
//每个窗口卖票的操作
//窗口 永远开启
while(true){
synchronized (lock) {
if(ticket>0){ //有票 可以卖
//出票操作
//使用sleep模拟一下出票时间
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
//获取当前线程对象的名字
String name = Thread.currentThread().getName();
System.out.println(name+”正在卖:”+ticket‐‐);
}
}
当使用同步代码块后,上述的线程安全问题就解决了。
同步方法:
使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外
格式:
Public synchronzed void method(){
可能会产生线程安全问题的代码:
}
同步锁是谁?
对于非static方法,同步锁就是this。
对于static方法,我们使用当前方法所在类的字节码对象(类名.class)。
代码:
public class Ticket implements Runnable{
private int ticket = 100;
//执行卖票操作

@Override
public void run() {
//每个窗口卖票的操作
//窗口 永远开启
while(true){
sellTicket();
}
}
锁对象 是 谁调用这个方法 就是谁
隐含 锁对象 就是 this
public synchronized void sellTicket(){
if(ticket>0){ //有票 可以卖
//出票操作
//使用sleep模拟一下出票时间
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto‐generated catch block
e.printStackTrace();
}
//获取当前线程对象的名字
String name = Thread.currentThread().getName();
System.out.println(name+”正在卖:”+ticket‐‐);
}
}
}
Lock锁:
机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作, 同步代码块/同步方法具有的功能Lock都有,除此之外更强大,更体现面向对象。 Lock锁也称同步锁,加锁与释放锁方法化了,如下:
public void lock() :加同步锁。
public void unlock() :释放同步锁。
代码:
public class Ticket implements Runnable{
private int ticket = 100;
Lock lock = new ReentrantLock();
//执行卖票操作
@Override
public void run() {
//每个窗口卖票的操作
//窗口 永远开启
while(true){
lock.lock();
if(ticket>0){ //有票 可以卖
//出票操作
//使用sleep模拟一下出票时间
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto‐generated catch block
e.printStackTrace();
}
//获取当前线程对象的名字
String name = Thread.currentThread().getName();
System.out.println(name+”正在卖:”+ticket‐‐);
}
lock.unlock();
}
}
}
第三章:线程状态:

1).新建:MyThread t = new MyThread();
2).可运行(待运行):t.start();
3).锁阻塞:运行后调用某个方法,但此方法已被其他线程“锁上了”。
4).无限等待:运行后,调用了“锁的wait()”方法。
5).计时等待:运行后,被调用了sleep(…);
6).被终止:run()方法正常运行完毕。
Timed Waiting(计时等待)
1. 进入 TIMED_WAITING 状态的一种常见情形是调用的 sleep 方法,单独的线程也可以调用,不一定非要有协
作关系。
2. 为了让其他线程有机会执行,可以将Thread.sleep()的调用放线程run()之内。这样才能保证该线程执行过程
中会睡眠
3. sleep与锁无关,线程睡眠到期自动苏醒,并返回到Runnable(可运行)状态。

小提示:sleep()中指定的时间是线程不会运行的最短时间。因此,sleep()方法不能保证该线程睡眠到期后就
开始立刻执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值