多线程详解

多线程详解

本篇文章同步学习:狂神说多线程讲解

线程简介

多任务

​ 多任务处理是指用户可以在同一时间内运行多个应用程序,每个应用程序被称作一个任务~

多线程

​ 多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。比如:在网抑云上一边听歌一边评论~

进程

​ 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位;比如:一个程序的运行,就是一个进程~

一个进程中有多个线程

线程实现(重点)

Thread:继承Thread

  1. 自定义线程类继承Thread类
  2. 重写run()方法,编写线程执行体
  3. 创建线程对象,调用start()方法启动线程
//继承Thread类
public class TestThread extends Thread{
    //重写run方法
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i <20 ; i++) {
            System.out.println("深夜学习~~~~~"+i);
        }
    }
    //主线程
    public static void main(String[] args) {
        //创建线程对象,调用start()方法启动线程
        TestThread testThread = new TestThread();
        testThread.start();
        
        for (int i = 0; i < 20; i++) {
            System.out.println("加油学习~~~~~"+i);
        }
    }

不建议使用:避免OOP单继承的局限性

Runnable:实现Runnable接口

  1. 自定义线程类实现Runnable接口
  2. 实现run()方法,编写线程执行体
  3. 创建线程对象,放进Thread对象中,并调用start()方法启动线程
//自定义线程类实现Runnable接口
public class TestRunnable implements Runnable{
    //实现run()方法,编写线程执行体
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i <20 ; i++) {
            System.out.println("深夜学习~~~~~"+i);
        }
    }
    //主线程
    public static void main(String[] args) {
        //创建线程对象,放进Thread对象中,并调用start()方法启动线程
        TestRunnable testRunnable = new TestRunnable();
        new Thread(testRunnable).start();
        for (int i = 0; i < 20; i++) {
            System.out.println("加油学习~~~~~"+i);
        }
    }
}

ps:new Thread(testRunnable).start();等同于Thread thread = new Thread(testRunnable);thread.start();这是静态代理模式的体现

这是静态代理模式的体现(Thread实现了Runnable接口,TestRunnable也实现了Runna接口)

推荐使用:避免单继承局限性,灵活方便,方便同一对象被多个线程使用

Callable:实现Callable接口

  1. 实现Callable接口,需要返回值类型

  2. 实现call方法,需要抛出异常

  3. 创建目标对象

  4. 创建执行服务

    ExecutorService ser = Executors.newFixedThreadPool(1);
    
  5. 提交执行

    Future<String> result = ser.submit(testCallable);
    
  6. 获取结果

    String r = result.get();
    
  7. 关闭服务

    ser.shutdownNow();
    
//1.实现Callable接口
public class TestCallable implements Callable<String>{
    //2.实现call方法,需要抛出异常
    @Override
    public String call(){
        System.out.println("wzf");
        return "wzf";
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //3.创建目标对象
        TestCallable testCallable = new TestCallable();
        //4.创建执行服务
        ExecutorService ser = Executors.newFixedThreadPool(1);
        //5.提交执行
        Future<String> result = ser.submit(testCallable);
        //6.获取结果
        String r = result.get();
        //7.关闭服务
        ser.shutdownNow();
    }
}

静态代理

  1. 真实对象和代理对象要实现同一接口

  2. 代理要代理真实角色

    优点:

    • 代理对象可以做很多真实对象做不了的事情
    • 真实对象专注自己的事情
public class StaticProxy {
    public static void main(String[] args) {
        //8.实例代理对象,并执行方法
        ProxyYou proxyYou = new ProxyYou(new you());
        proxyYou.HappyMarry();
    }
}
//1.共同的接口
interface Marry{
    void HappyMarry();
}
//2.本身
class you implements  Marry{
    //实现接口
    @Override
    public void HappyMarry() {
        System.out.println("本人非常开心~");
    }
}
//3.代理对象
class ProxyYou implements Marry{
    //4.目标对象
    private Marry target;
    //5.构造方法
    public ProxyYou(Marry target) {
        this.target = target;
    }
    //实现接口
    @Override
    public void HappyMarry() {
        System.out.println("代理你,结婚前");
        //6.调用目标对象方法
        this.target.HappyMarry();
        //7.aop思想
        System.out.println("代理你,结婚后");
    }
}

对比

 		//8.实例代理对象,并执行方法
        new ProxyYou(new you()).HappyMarry();
        //对比
        new Thread(()->{ System.out.println("和上面的静态代理如出一辙"); }).start();

Lamda表达式

  • λ希腊字母表中排序第十一位的字母,英语名称为Lamda

  • 避免匿名内部类定义过多

  • 其实质属于函数式编程的概念

  • 前提是函数式接口才能用lamda表达式

    函数式接口的定义

    ​ 任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口

    ​ 例如:Runnable接口源码:

    @FunctionalInterface
    public interface Runnable {
        public abstract void run();
    }
    

    对于函数式接口,我们可以通过lamda表达式来创建该接口的对象;

    原来我们的习惯是:

    //推导lamda表达式
    public class TestLamda {
        public static void main(String[] args) {
            //3.接口new实现类
            StudyLamda you = new You();
            you.onlyone();
        }
    }
    //1.定义一个函数式接口
    interface StudyLamda{
        //接口里的方法是抽象的,只包含一个抽象方法
        void onlyone();
    }
    //2.实现类
    class You implements StudyLamda{
        @Override
        public void onlyone() {
            System.out.println("你正在学习lamda表达式");
        }
    }
    

    静态内部类

    //推导lamda表达式
    public class TestLamda {
        //2.静态内部类
        static class You implements StudyLamda{
            @Override
            public void onlyone() {
                System.out.println("你正在学习lamda表达式");
            }
        }
        public static void main(String[] args) {
            //3.接口new实现类
            StudyLamda you = new You();
            you.onlyone();
        }
    }
    //1.定义一个函数式接口
    interface StudyLamda{
        //接口里的方法是抽象的,只包含一个抽象方法
        void onlyone();
    }
    

    局部静态类

    //推导lamda表达式
    public class TestLamda {
        public static void main(String[] args) {
            //4.局部内部类
            class You implements StudyLamda{
                @Override
                public void onlyone() {
                    System.out.println("你正在学习lamda表达式");
                }
            }
            //3.接口new实现类
            StudyLamda you = new You();
            you.onlyone();
        }
    }
    //1.定义一个函数式接口
    interface StudyLamda{
        //接口里的方法是抽象的,只包含一个抽象方法
        void onlyone();
    }
    
    

    匿名内部类:

    //推导lamda表达式
    public class TestLamda {
        public static void main(String[] args) {
            //匿名内部类
            StudyLamda studylamda = new StudyLamda() {
                @Override
                public void onlyone() {
                    System.out.println("你正在学习lamda表达式");
                }
            };
            studylamda.onlyone();
        }
    }
    //1.定义一个函数式接口
    interface StudyLamda{
        //接口里的方法是抽象的,只包含一个抽象方法
        void onlyone();
    }
    

    最终简化

    public class TestLamda {
        //2.静态内部类
        public static void main(String[] args) {
            //lamda表达式
            StudyLamda studyLamda = ()->{
                System.out.println("你正在学习lamda表达式~");
            };
            studyLamda.onlyone();
        }
    }
    //1.定义一个函数式接口
    interface StudyLamda{
        //接口里的方法是抽象的,只包含一个抽象方法
        void onlyone();
    }
    

    lamda表达的简化:

    public class TestLamda2 {
        public static void main(String[] args) {
              A a = (String s)->{
                      System.out.println("lamda的简化过程!"+s);
              };
            //去掉参数类型
            a = (s)->{
                System.out.println("lamda的简化过程!"+s);
            };
            //简化括号
            a = s->{
                System.out.println("lamda的简化过程!"+s);
            };
            //简化花括号
            a = s->System.out.println("lamda的简化过程!"+s);
            a.B("4");
            /*
            总结:lamda表达式只能有一行代码情况下才能简化,前提是函数式接口
                参数可以去掉类型,要去掉就都去掉,多个要加括号
             */
        }
    }
    interface A{
        void B(String s);
    }
    

线程状态

5大状态

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-66wYJICI-1599924615953)(C:\Users\王智芳\Desktop\截图\ThreadStats.jpg)]

线程停止

  1. 建议线程正常停止,利用次数,不建议死循环
  2. 建议使用标志位,设置一个标志位
  3. 不要使用stop或者destroy等过时或者jdk不建议使用的方法
public class TestStop implements Runnable{
    //设置标志位
    private boolean flag = true;
    @Override
    public void run() {
        int i = 0;
        while (flag){
            System.out.println("ThreadStop!"+i++);
        }
    }
    public void s(){
        this.flag = false;
    }
    public static void main(String[] args) {
        TestStop testStop = new TestStop();
        new Thread(testStop).start();
        for (int i = 0; i < 800; i++) {
            //注意写上这个输出操作,不然时间太快,效果不能显示
            System.out.println("main"+i);
            if(i == 600){
                testStop.s();
                System.out.println("主线程中让线程停止了");
            }
        }
    }
}

线程休眠

  • sleep(时间)指定当前线程阻塞的毫秒数
  • sleep存在异常interruptedexeception
  • sleep时间到达后线程进入就绪状态
  • sleep可以模拟网络延时,倒计时等
  • 每一个对象都有一个锁,sleep不会释放锁
            //模拟延时,扩大问题的发生性
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

线程礼让(yield)

  • 礼让线程,让当前正在执行的线程暂停,但不阻塞
  • 将线程从运行状态转为就绪状态
  • 让CPU重新调度,礼让不一定成功,看CPU心情
public class TestYield {
    public static void main(String[] args) {
        MyYield myYield = new MyYield();
        new Thread(myYield,"A").start();
        new Thread(myYield,"B").start();
    }
}
class MyYield implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"输出完之后会礼让");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"礼让不一定成功");
    }
}

线程强制执行(join)

public class TestJoin implements Runnable{
    @Override
    public void run() {
        System.out.println("vip的线程来了~");
    }

    public static void main(String[] args) {
        TestJoin testJoin = new TestJoin();
        Thread thread =new Thread(testJoin);
        thread.start();
        //主线程
        for (int i = 0; i < 100; i++) {
            System.out.println("主线程"+i);
            if(i == 80){
                try {
                    //插队,可能会让线程阻塞
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

线程观测状态

  • 线程状态。线程可以处于以下状态之一:
    • NEW
      尚未启动的线程处于此状态。
    • RUNNABLE
      在Java虚拟机中执行的线程处于此状态。
    • BLOCKED
      被阻塞等待监视器锁定的线程处于此状态。
    • WAITING
      正在等待另一个线程执行特定动作的线程处于此状态。
    • TIMED_WAITING
      正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。
    • TERMINATED
      已退出的线程处于此状态。
   Thread.State state = thread.getState();

死亡之后的线程不能启动

线程的优先级(PRIORITY)

线程优先级1~10

public class TestPriority implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"----------->"+Thread.currentThread().getPriority());
    }

    public static void main(String[] args) {
        TestPriority testPriority = new TestPriority();
        System.out.println(Thread.currentThread().getName()+"----------->"+Thread.currentThread().getPriority());
        Thread a = new Thread(testPriority);
        Thread b = new Thread(testPriority);
        Thread c = new Thread(testPriority);
        //设置优先级,再启动
        a.setPriority(3);
        a.start();

        b.setPriority(Thread.MAX_PRIORITY);
        b.start();

        c.setPriority(Thread.MIN_PRIORITY);
        c.start();
    }
}

优先级低只意味着获得调度的概率低,并不是优先级低就不会被调用了。这都是蓝CPU的调度

守护线程

  • 线程分为用户线程和守护线程
  • 虚拟机必须确保用户线程执行完毕
  • 虚拟机不用等待守护线程执行完毕
  • 如:后台记录操作日志,垃圾回收等等。。。
//守护线程
public class TestGuard {
    public static void main(String[] args) {
        You you = new You();
        God god = new God();

        Thread b = new Thread(god);
        //默认是false,true之后为守护线程
        b.setDaemon(true);
        b.start();
        new Thread(you).start();
    }
}
//用户线程
class You implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("用户线程正在执行");
        }
        System.out.println("gameover");
    }
}
//守护线程
class God implements Runnable{

    @Override
    public void run() {
        while(true){
            System.out.println("我是守护线程,守护着你");
        }
    }
}

线程同步(synchronized)

并发:多个线程操作同一个资源

三大不安全实例

1.买票问题

public class UnsafeBuyTicket implements Runnable{
    private int ticket = 10;
    @Override
    public void  run() {
        while(true){
            if(ticket<=0){
                break;
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"买了"+ticket--);
        }
    }

    public static void main(String[] args) {
        UnsafeBuyTicket unsafeBuyTicket = new UnsafeBuyTicket();
        new  Thread(unsafeBuyTicket,"A").start();
        new  Thread(unsafeBuyTicket,"B").start();
        new  Thread(unsafeBuyTicket,"C").start();
    }
}

**解决办法:不会~但是应该synchronized解决此类问题 **

可以使用lock,查看下面Lock(ReentrantLock)

2.银行问题

public class UnsafeBank {
    public static void main(String[] args) {
        Acount acount = new Acount(100,"wzf");
        Bank ba = new Bank(acount,70,"ba");
        Bank ma = new Bank(acount,70,"ma");
        ba.start();
        ma.start();
    }

}
//账户
class Acount{
     int money;//余额
     String name;//卡名
    public Acount(int money, String name) {
        this.money = money;
        this.name = name;
    }
}
class Bank extends Thread{
    Acount acount;
    int quqian;//取多少钱
    int nowqian;//手里多少钱

    public Bank(Acount acount, int quqian, String name) {
        super(name);
        this.acount = acount;
        this.quqian = quqian;

    }
    @Override
    public   void run() {
         //判断有没有钱
            if(acount.money - quqian<0){
                System.out.println("余额不足");
                return;
            }
            try {
                //扩大事情的发生性
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            acount.money = acount.money - quqian;
            nowqian = nowqian + quqian;
            System.out.println(acount.name+"余额为"+acount.money);
            System.out.println(this.getName()+"手上有:"+nowqian);

    }

解决办法:synchronized 代码块

synchronized(acount){}//锁住增删改查的对象

3.集合问题

public class UnsafeList {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        System.out.println(list.size());
    }
}

解决办法:synchronized 代码块

synchronized(list){}//锁住增删改查的对象

JUC下的CopyOnWriteArryList也行;

同步代码块会引起死锁

死锁

​ 死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

产生死锁的原因:
  (1) 因为系统资源不足。
  (2) 进程运行推进的顺序不合适。
  (3) 资源分配不当等。

产生死锁的四个必要条件:

  1. 互斥条件:一个资源每次只能被一个进程使用。

  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

  3. 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺

  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系

    这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。

//死锁:多个线程互相抱着对方需要的资源,然后形成僵持
public class DeadLock {
    public static void main(String[] args) {
        MakeUp aaa = new MakeUp(0,"A");
        MakeUp bbb = new MakeUp(2,"B");
        new Thread(aaa).start();
        new Thread(bbb).start();
    }
}
//镜子
class Mirror{
}
//口红
class Lipstick{
}
class MakeUp implements Runnable{
    static Mirror mirror = new Mirror();
    static Lipstick lipstick = new Lipstick();
    int choose;
    String name;

    public MakeUp(int choose, String name) {
        this.choose = choose;
        this.name = name;
    }
    private void makeup(){
        if(choose==0){
            synchronized (mirror){
                System.out.println(Thread.currentThread().getName()+"锁住了mirror");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lipstick){
                    System.out.println(Thread.currentThread().getName()+"一秒后锁住了lipstick");
                }
            }
        }else {
            synchronized (lipstick){
                System.out.println(Thread.currentThread().getName()+"锁住了lipstick");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (mirror){
                    System.out.println(Thread.currentThread().getName()+"一秒后锁住了mirror");
                }
            }
        }
    }
    @Override
    public void run() {
        makeup();
    }
}

Lock(ReentrantLock)

public class BuyTicket implements Runnable{
    private int ticket = 10;
    //定义锁
    private final ReentrantLock lock = new ReentrantLock();
    @Override
    public void  run() {
        while(true){
            lock.lock();
            try {
                if(ticket<=0){
                    break;
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"买了"+ticket--);
            }
            finally {
                lock.unlock();
            }

        }
    }

    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();
        new  Thread(buyTicket,"A").start();
        new  Thread(buyTicket,"B").start();
        new  Thread(buyTicket,"C").start();
    }
}

线程通信

生产者和消费者

生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的

管程法

设置缓冲区Refrigerator

//管程法------------->利用缓冲区解决
    //生产者,消费者,产品,缓冲区
public class Tube {
    public static void main(String[] args) {
        Refrigerator refrigerator = new Refrigerator();
        Producer producer = new Producer(refrigerator);
        Consumer consumer = new Consumer(refrigerator);
        new Thread(producer).start();
        new Thread(consumer).start();
    }
}
//生产者
class Producer implements Runnable{
    Refrigerator refrigerator;

    public Producer(Refrigerator refrigerator) {
        this.refrigerator = refrigerator;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            refrigerator.put(new Chicken(i));
            System.out.println("生产了第------》"+i);
        }
    }
}
//消费者
class Consumer implements Runnable{
    Refrigerator refrigerator;

    public Consumer(Refrigerator refrigerator) {
        this.refrigerator = refrigerator;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消费了第------------------------------》"+refrigerator.out().number);
        }
    }
}
//产品
class Chicken{
    //标识第几只
    int number;

    public Chicken(int number) {
        this.number = number;
    }
}
//缓冲区
class Refrigerator{
    Chicken[] chickens = new Chicken[10];
    //计数器
    int count = 0;
    //放入
    synchronized void put(Chicken chicken){
        if(count==10){
            //容器满了等待消费者西消费
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        chickens[count] = chicken;
        count++;
        this.notify();
    }
    //拿出
    synchronized Chicken out(){
        if(count==0){
            //容器空了,通知生产者生产
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        count--;
        Chicken chicken = chickens[count];
        this.notify();
        return chicken;
    }
}
信号灯法

设置标志位:flag

public class Signal {
    public static void main(String[] args) {
        Chicken1 chicken1 = new Chicken1();
        Consumer1 consumer1 = new Consumer1(chicken1);
        Producer1 producer1 = new Producer1(chicken1);
        new Thread(producer1).start();
        new Thread(consumer1).start();
    }
}
//生产者
class Producer1 implements Runnable{
    Chicken1 chicken1;

    public Producer1(Chicken1 chicken1) {
        this.chicken1 = chicken1;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if(i%2==0){
                this.chicken1.put(1);
            }
            else{
                this.chicken1.put(2);
            }
        }
    }
}
//消费者
class Consumer1 implements Runnable{
    Chicken1 chicken1;

    public Consumer1(Chicken1 chicken1) {
        this.chicken1 = chicken1;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            this.chicken1.out();
        }
    }
}
//产品
class Chicken1{
    //标识符
    boolean flag = true;
    //标识第几只
    int number;
    //放入
    synchronized void put(int j){
        if(!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("生产-----》"+j);
        this.number = j;
        this.notifyAll();
        this.flag = !this.flag;
    }
    //拿出
    synchronized void out(){
        if(flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("消费--------------------------------------》"+number);
        this.notifyAll();
        this.flag = !this.flag;
    }
}

高级主题

线程池

一、一句话说明白shutdown和shutdownNow的区别

shutdown只是将线程池的状态设置为SHUTWDOWN状态,正在执行的任务会继续执行下去,没有被执行的则中断。

而shutdownNow则是将线程池的状态设置为STOP,正在执行的任务则被停止,没被执行任务的则返回。

文章参考:[线程池中shutdown()和shutdownNow()方法的区别](https://www.cnblogs.com/aspirant/p/10265863.html)

线程池例子:

public class TestPool {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(10);
        
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());

        service.shutdown();
    }
}
class MyThread implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

日记

2020.9.9 上午吃了一个鸡蛋饼去上大数据技术,下午上机温习了Linux的命令,晚上

写了大数据的作业,但是对于Shell脚本完成java环境配置不会,有机会要学习一下,一天就这样茫然的过去了~

2020.9.10 今天是教师节,回忆起以前老师,感慨万千,吃完早餐,和室友去修复宽带,然后看了十几集多线程,优化了许多内容无聊时还和室友打了两把游戏队友太菜了~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值