什么是线程
线程又称“轻量级进程”,是程序中一个顺序控制流程,同时也是CPU的基本调度单位。进程由多个线程组成,彼此间完成不同的工作,交替执行成为多线程。
线程的组成
任何一个线程都具有基本的组成部分:CPU时间片(操作系统OS会为每个线程分配执行空间)、运行数据(堆空间—存储线程使用的对象,多个线程可以共享堆中对象;栈空间—存储线程使用的局部变量,每个线程都有自己的栈。)
创建线程的方式
(1)继承Thread类
public class TestExendsThread {
public static void main(String[] args) {
MyThread1 m1=new MyThread1();
MyThread2 m2=new MyThread2(); //创建子类对象
// m1.run();
// m2.run(); //错误,普通方法调用
m1.start(); //调用start方法
m2.start(); //启动线程
for (int i=0;i<50;i++){
System.out.println("main: "+i);
}
System.out.println("运行结束!!!");
}
}
class MyThread1 extends Thread{ //继承Thread类
public void run(){ //覆盖run方法
for (int i=0;i<50;i++){
System.out.println("MyThread1: "+i);
}
}
}
class MyThread2 extends Thread{
public void run(){
for (int i=0;i<50;i++){
System.out.println("MyThread2: "+i);
}
}
}
(2)实现Runnable接口
public class TestRunnable {
public static void main(String[] args) {
Myrunnable task=new Myrunnable(); //创建实现类对象
Thread t1=new Thread(task); //创建线程对象
Thread t2=new Thread(task);
t1.start(); //调用start方法
t2.start();
}
}
class Myrunnable implements Runnable{ //实现Runnable接口
@Override
public void run(){ //覆盖run方法
for (int i=0;i<50;i++){
System.out.println(Thread.currentThread().getId()+" : "+i);
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
常见方法
- 休眠
- public static void sleep(long millis)
- 当前线程休眠多少毫秒。
- 放弃
- public static void yield()
- 主动放弃时间片,回到就绪状态,竞争下一次时间片。
- 结合
- public final void join()
- 允许其他线程加入到当前线程中,并优先执行。
实例:
public class TestMthreadMothod {
public static void main(String[] args) {
Thread t1=new Thread(new Task1());
Thread t2=new Thread(new Task2());
t1.start();
t2.start();
}
}
class Task1 implements Runnable{
@Override
public void run(){
for (int i=0;i<400;i++){
System.out.println("Task1: "+i);
}
}
}
class Task2 implements Runnable{
@Override
public void run(){
for (int i=0;i<400;i++){
System.out.println("-----Task2:"+i);
if(i%10==0){
Thread.yield(); //主动放弃时间片
}
}
}
}
线程的状态(等待)
线程不安全
- 当多线程并发访问临界资源时,如果破坏原子操作,可能会造成数据不一致。
- 临界资源:共享资源(同一对象),一次仅允许一个线程使用,才可保证其正确性。
- 原子操作:不可分割的多步操作,被视作一个整体,其顺序和步骤不可打乱或缺省。
同步方式1
同步代码块:
synchroized(临界资源对象){ //对临界资源对象加锁
//代码(原子操作)
}
注意:
- 每个对象都有一个互斥锁标记,用来分配给线程。
- 只有拥有对象互斥锁标记的线程,才能进入对该对象加锁的同步代码块。
- 线程退出同步代码块,会释放相应的互斥锁标记。
线程状态(阻塞)
实例:
public class TestSynchorized {
public static void main(String[] args) {
Account a1=new Account("lly","1234",1204.4);
Husband h=new Husband(a1);
Wife w =new Wife(a1);
Thread t1=new Thread(h);
Thread t2=new Thread(w);
t1.start();
t2.start();
}
}
class Husband implements Runnable{
private Account acc;
public Husband(Account acc){
this.acc=acc;
}
@Override
public void run(){
synchronized (acc){
this.acc.withdrawal("lly","1234",880.5);
}
}
}
class Wife implements Runnable{
private Account acc;
public Wife(Account acc){
this.acc=acc;
}
@Override
public void run(){
synchronized (acc){
this.acc.withdrawal("lly","1234",880.5);
}
}
}
class Account{
String carno;
String password;
double balance;
public Account(String carno,String password,double balance){
super();
this.carno=carno;
this.password=password;
this.balance=balance;
}
public void withdrawal(String no,String pwd,double money){
System.out.println("请稍后!!!");
if(no==carno&&pwd==password){
System.out.println("-----------登陆成功!!!!---------");
if (money<balance){
balance-=money;
System.out.println("@@@@取款成功!@@@@"+"\n余额为:"+balance);
}else{
System.out.println("^^^^^余额不足!^^^^^");
}
}else{
System.out.println("-----------登录失败!!!!---------");
}
}
}