线程

  创建并启动一个线程的方法
        1) 实现接口的方式
        ① 写一个具体类, 实现Runnable接口, 并实现其中的run方法,这个run方法就是线程的入口方法
        ② 创建这个类的对象, 并以这个对象为实参, 创建Thread类的对象
        ③ 调用Thread对象的start()方法 启动线程
/**
 * 多线程打印偶数,奇数
 */
public class ThreadTest {
    public static void main(String[] args) {
        //利用一个Runnable引用可以创建多个线程,只不过这几个线程共用一个run方法
        //但是属于不同的线程,线程创建好的标志,有了栈
        //多态
        Runnable r = new PrintEven();
        Thread t1 = new Thread(r);
        t1.setName("子线程1");
        t1.start();
        //lamda表达式形式
        new Thread(()->{
            for(i = 0; i < 100; i += 2) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }).start();
        //end

        Thread t2 = new Thread(r);
        t2.setName("子线程2");
        t2.start();

        Runnable r2 = new PrintOdd();
        Thread tt = new Thread(r2);
        tt.setName("子线程A");
        tt.start();
    }
}

//子线程打印偶数0~100
class PrintEven implements Runnable{

    private int i ;

    @Override
    public void run() {
        /*
         * 该线程要做的事,打印0~100的所有偶数
         */
        for(i = 0; i < 100; i += 2) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}
//子线程打印奇数0~100
class PrintOdd implements Runnable{

    private int i ;

    @Override
    public void run() {
        /*
         * 该线程要做的事情
         */
        for(i = 1; i < 100; i += 2) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}
/**
 * 创建线程的第二种方式:
 *      继承的方式
 *      1) 写一个具体类继承自Thread, 重写run方法, 这个run方法是真的入口
 *      2) 创建具体类对象, 相当于创建了Thread对象
 *      3) 调用Thread对象的.start()
 */
class TestThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(currentThread().getName() + " : " + i);
        }
    }
}
public class ThreadTest {
    public static void main(String[] args) {
        //自定义子线程
        new TestThread().start();
        //main线程
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}
/**
 * 1.在main方法中创建并启动一个线程,线程循环随机打印100以内的整数,直到主线程从键盘读取了"Q"命令
 * 
 */
import java.util.Scanner;

public class GetRandomNumTest {
    public static void main(String[] args) {
        //创建线程
        //利用实现Runnable接口创建线程本质还是创建Thread对象,(利用Runnable引用创建对象)
        /*
         *     public Thread(Runnable target) {
         *          init(null, target, "Thread-" + nextThreadNum(), 0);
         *     }
         */
        //多态
        Runnable r = new GetRandomNum();
        Thread t = new Thread(r);
        //开启线程
        t.start();
        //创建输入流从键盘获取信息
        Scanner sc = null;
        try {
            sc = new Scanner(System.in);
            while(sc.hasNext()) {
                String str = sc.nextLine();
                //不区分大小写
                if(str.equalsIgnoreCase("Q")) {
                    ((GetRandomNum)r).setStopflag(true);
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //对于Scanner对象关流不需要处理异常
            sc.close();
        }
    }
}
/*
 * 线程循环随机打印100以内的整数,直到主线程从键盘读取"Q"
 */
class GetRandomNum implements Runnable {

    private boolean stopflag = false;

    public boolean isStopflag() {
        return stopflag;
    }

    public void setStopflag(boolean stopflag) {
        this.stopflag = stopflag;
    }
    @Override
    public void run() {
        /*
         * 因为线程要循环随机打印100以内的整数,直到主线程从键盘获取"Q"
         * 因此并不知道线程体中要循环多少次,要设置无限循环
         * 同时因为要从外界来终止循环,所以要设置一个控制循环的布尔变量,当外界条件满足是修改布尔变量值,使得循环终止
         */
        while(!stopflag) {
            //打印当前线程名字和生成的随机整数
            System.out.println(Thread.currentThread().getName() + ":" + (int)(Math.random() * 100));
        }
    }
}
import java.io.BufferedReader;
import java.io.InputStreamReader;

/**
 * 2.在main方法中启动两个线程。第一个线程循环随机打印100以内的整数,直到第二个线程从键盘读取了"Q"命令
 * 将线程将要执行的任务放在线程体中
 */
public class GetRandomNumTest2 {
    public static void main(String[] args) {
        Runnable r = new GetRandomNumber();
        Thread t = new Thread(r);

        Runnable r1 = new KeyListener((GetRandomNumber)r);
        Thread t1 = new Thread(r1);

        t.start();
        t1.start();
    }
}

class GetRandomNumber implements Runnable {

    private boolean stopflag = false;

    public boolean isStopflag() {
        return stopflag;
    }

    public void setStopflag(boolean stopflag) {
        this.stopflag = stopflag;
    }

    @Override
    public void run() {
        while(!stopflag) {
            int randomNum = (int)(Math.random() * 100);
            System.out.println(Thread.currentThread().getName() + "  " + randomNum);
        }
    }
}
/*
 * 再设置一个线程控制循环结束,通过不断的监听键盘数据,进行判断,然后对循环进行控制
 */
class KeyListener implements Runnable {

    private GetRandomNumber getRandomNumber;

    public KeyListener(GetRandomNumber getRandomNumber) {
        this.getRandomNumber = getRandomNumber;
    }
    @Override
    public void run() {
        //设置输入流,从键盘获取信息,然后判断,对循环进行控制
        InputStreamReader isr = null;
        BufferedReader bfr = null;
        try {
            isr = new InputStreamReader(System.in);
            bfr = new BufferedReader(isr);
            //方法2
            String string = bfr.readLine();
            while(true) {
                if(string.equalsIgnoreCase("Q")) {
                    getRandomNumber.setStopflag(true);
                    break;
                }
                string = bfr.readLine();
            }
            /*方法1
            //从键盘获取信息
            String string = bfr.readLine();
            //若不是q继续获取
            while(!string.equalsIgnoreCase("Q")) {
                string = bfr.readLine();
            }
            getRandomNumber.setStopflag(true);
            */
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                bfr.close();
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
    }
}
import java.util.ArrayList;
import java.util.List;
/**
 * 1.编写程序,在main中创建一个线程。线程每隔一定时间(200ms以内的随机时间)产生一个0~100之间的随机整数
 * 打印后将该整数放到集合中,共产生100个整数,全部产生后,睡眠30秒,然后将集合内容打印输出
 * 在main线程中,唤醒上述睡眠的线程,使其尽快打印集合内容
 * 
 * 首先要先构建目标线程类,在线程体中实现线程需要做的事情。
 * 然后利用main线程唤醒
 *实现精准控制,boolean变量
 */
public class GetDataTest {
    public static void main(String[] args) {
        //创建获取整数的线程
        Runnable r = new GetData();
        Thread t = new Thread(r);
        t.start();
        /*
        //在main中实现精准控制打断
        while(!((GetData)r).isFlag()) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //当flag为true时,while循环结束执行下面语句,下面这个语句打断睡觉
        t.interrupt();
        */
        //利用另一个线程做打断的工作
        Runnable r1 = new Keylisten((GetData)r, t);
        Thread t1 = new Thread(r1);
        t1.start();
    }
}
/*
 * 线程的任务,将这些任务写在线程的run方法中就行
 * 线程每隔一定时间(200ms以内的随机时间)产生一个0~100之间的随机整数
 * 打印后将该整数放到集合中,共产生100个整数,全部产生后,睡眠30秒,然后将集合内容打印输出
 */
class GetData implements Runnable {
    //因为需要从外界将线程唤醒,需要设置一个标记
    private boolean flag = false;

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        /*
         * 该类线程完成的任务
         */
        //创建一个list集合保存生成的随机数
        List<Integer> list = new ArrayList<Integer>();
        //需要生成100个随机数
        for(int i = 0; i < 100; i++) {
            //获取随机整数
            int randomNum = (int)(Math.random() * 100);
            //打印随机整数
            System.out.println(randomNum);
            //保存到集合中
            list.add(randomNum);
            //睡觉
            try {
                //获取随机的睡觉时间
                long randomTime = (int)(Math.random() * 200);
                //睡觉
                Thread.sleep(randomTime);
            } catch (InterruptedException e) {
                //处理睡觉被打断异常
                System.out.println("小睡被打断");
            }
        }
        //当数据生成完成后,将flag修改,便于外界唤醒线程
        flag = true;
        //全部完成后,睡一大觉
        try {
            Thread.sleep(30 * 1000);
        } catch (InterruptedException e) {
            System.out.println("长睡被打断");
        }
        //遍历打印集合
        for (Integer integer : list) {
            System.out.print(integer + " ");
        }
    }
}

class Keylisten implements Runnable {
    //对于对象关联,先写方法,需要什么,就关联什么
    //关联两个类
    private GetData r;
    private Thread t;
    public Keylisten(GetData r, Thread t) {
        this.r = r;
        this.t = t;
    }
    @Override
    public void run() {
        /*
         * 这个线程要精准的唤醒获取数据的线程
         */
        while(!((GetData)r).isFlag()) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        t.interrupt();
    }
}
/**
 * 银行有一个账户Account包含属性name, balance
 * 有两个柜台分别同时向同一个账户存3000元,每次存1000,存3次。每次存完打印账户余额。睡眠10毫秒
 * 
 * 问题:该程序是否有安全问题,如果有,如何解决?
 * 
 * 一个柜台Deposit存3000元, 每次存1000,存3次 另一个柜台Withdraw取3000元, 每次取1000,取3次
 */
/*
 * 一个柜台就是一个线程,将账户与存取钱操作分开
 */
public class Account {

    private String name;
    private int balance;

    public Account() {
    }

    public Account(String name, int balance) {
        super();
        this.name = name;
        this.balance = balance;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getBalance() {
        return balance;
    }

    public void setBalance(int balance) {
        this.balance = balance;
    }

    @Override
    public String toString() {
        return "Account [name=" + name + ", balance=" + balance + "]";
    }
}
/*
 * 一个柜台Deposit存3000元, 每次存1000,存3次 另一个柜台Withdraw取3000元, 每次取1000,取3次
 * 有两个柜台分别同时向同一个账户存3000元,每次存1000,存3次。每次存完打印账户余额。睡眠10毫秒
 * 每一个柜台相当于一个线程,对于存款,取款操作不同,因此需要不同的线程类
 */
public class Deposit implements Runnable{

    private Account account;

    public Deposit(Account account) {
        this.account = account;
    }
    @Override
    public void run() {
        synchronized ("") {
            for(int i = 0; i < 3; i++) {
                account.setBalance((account.getBalance() + 1000));
                System.out.println(Thread.currentThread().getName() + "  " + "账户余额:" + account.getBalance());
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    System.out.println("在睡觉时被打断。");
                }
            }
        }
    }
}
/*
 * 取钱柜台也相当于一个线程
 * 另一个柜台Withdraw取3000元, 每次取1000,取3次
 * 利用使用相同的同步锁将取钱和存钱同步
 */
public class Withdraw implements Runnable{

    private Account account;

    public Withdraw(Account account) {
        this.account = account;
    }
    @Override
    public void run() {
        synchronized ("") {
            for(int i = 0; i < 3; i++) {
                account.setBalance(account.getBalance() - 1000);
                System.out.println(Thread.currentThread().getName() + "  " + "账户余额:" + account.getBalance());
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    System.out.println("在休息时被打断");
                }
            }
        }
    }
}
/**
 * 测试类
 *
 */
public class AccountTest {
    public static void main(String[] args) {
        Account account = new Account("张三", 5000);

        Runnable rdeposit = new Deposit(account);
        Thread td1 = new Thread(rdeposit);
        td1.setName("存钱柜台A");
        td1.start();

        Thread td2 = new Thread(rdeposit);
        td2.setName("存钱柜台B");
        td2.start();

        Runnable rwithdraw = new Withdraw(account);
        Thread tw1 = new Thread(rwithdraw);
        tw1.setName("取钱柜台1");
        tw1.start();
    }
}
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值