概念
线程:线程是进程中的一个执行单元
进程:是指一个内存中运行的应用程序
线程的六个状态
- NEW 新建状态
- RUNNABLE 就绪状态
- BLOCKED 阻塞等待锁的线程状态
- WAITING 等待状态
- TIMED_WAITing 计时等待状态
- TERMINATED 终止状态
线程的创建:
(一)
Java使用 java.lang.Thread
类代表线程
自定义线程类:
public class MyThread extends Thread { //定义指定线程名称的构造方法
public MyThread(String name) {
//调用父类的String参数的构造方法,指定线程的名称 super(name);
}
/**
* 重写run方法,完成该线程执行的逻辑 */
@Override
public void run() {
for (int i = 0; i < 10; i++) { System.out.println(getName()+":正在执行!"+i);
} }}
开启线程可以调用线程的start方法
构建方法
public Thread() :分配一个新的线程对象。
public Thread(String name) :分配一个指定名字的新的线程对象。
public Thread(Runnable target) :分配一个带有指定目标新的线程对象。
public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。
常用方法
public String getName() :获取当前线程名称。
public void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。
public void run() :此线程要执行的任务在此处定义代码。
public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。 public static Thread currentThread() :返回对当前正在执行的线程对象的引用。
(二)
采用 java.lang.Runnable 也是非常常见的一种,我们只需要重写run方法即可。
public class MyRunnable implements Runnable{ @Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+" "+i); }
} }
public class Demo {
public static void main(String[] args) {
//创建自定义类对象 线程任务对象
MyRunnable mr = new MyRunnable();
//创建线程对象
Thread t = new Thread(mr, "小强");
t.start();
for (int i = 0; i < 20; i++) { System.out.println("旺财 " + i);
} }
}
Thread和Runnable的区别
匿名内部类方式实现线程的创建
Runnable r = new Runnable(){
public void run(){
for (int i = 0; i < 20; i++) {
System.out.println("张宇:"+i); }
} };
// 继承thread类实现多线程
new Thread() {
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println(Thread.currentThread().getName() + "--"
+ x);
}
}
}.start();
;
// 实现runnable借口,创建多线程并启动
new Thread(new Runnable() {
@Override
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println(Thread.currentThread().getName() + "--"
+ x);
}
}
}) {
}.start();
// 更有难度的,在Thread匿名内部类的里面再一次重写run方法
//在实际运行时的结果是 hello+x。以thread的run方法为准。但是此处无意义
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for (int x = 0; x < 100; x++) {
System.out.println("java" + "--" + x);
}
}
}) {
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println("hello" + "--" + x);
}
}
}.start();
}
利用Runnable可以实现多线程
同步代码块
synchronized(同步锁){
需要同步操作的代码
}
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) {
// TODO Auto‐generated catch block
e.printStackTrace(); }
//获取当前线程对象的名字
String name = Thread.currentThread().getName(); System.out.println(name+"正在卖:"+ticket‐‐);
} }
}
当使用了同步代码块后,上述的线程的安全问题,解决了。
同步方法 同步方法:使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外
等着。 格式:
同步锁是谁?
对于非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();
2.5 Lock锁
java.util.concurrent.locks.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(); }
} }